:root{--orange:#f26a1b;--blue:#1f5fbf;--navy:#0f1b2d;--bg:#f5f6f8;--ink:#1a2233;--mute:#6b7280;--line:#e3e6eb;--green:#1e9e5a;--red:#d33d3d;--amber:#d8901a}
*{box-sizing:border-box}
body{margin:0;font-family:'IBM Plex Sans',ui-sans-serif,'Segoe UI',system-ui,sans-serif;color:var(--ink);background:var(--bg);font-size:14px}
a{color:var(--blue)} a:hover{color:#174a97}
.app{display:flex;min-height:100vh}
.side{width:220px;background:var(--navy);color:#c9d2e0;display:flex;flex-direction:column;padding:18px 0;flex-shrink:0;position:sticky;top:0;height:100vh;overflow-y:auto}
.brand{display:flex;align-items:center;gap:10px;padding:0 18px 18px;border-bottom:1px solid #1f2d44}
.logo{width:30px;height:30px;border-radius:6px;background:var(--orange);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:13px;flex-shrink:0}
.brand b{color:#fff;font-size:15px;display:block} .brand span{font-size:11px;color:#8b98ad}
.store{margin:14px 14px 8px;background:#182640;border:1px solid #2a3a56;border-radius:6px;padding:8px 10px;color:#fff;font-size:13px}
.nav{display:flex;flex-direction:column;gap:2px;padding:6px 10px}
.nav a{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;font-size:13.5px;color:#c9d2e0;text-decoration:none}
.nav a:hover{background:#162438;color:#fff} .nav a.on{background:#1c2c48;color:#fff;box-shadow:inset 3px 0 0 var(--orange)}
.nav .grp{font-size:10.5px;letter-spacing:.08em;color:#6f7d94;padding:14px 10px 4px;text-transform:uppercase}
.main{flex:1;display:flex;flex-direction:column;min-width:0}
/* z-index 110, and the number is load-bearing (build 83J, Jon 9/13).
   `.top` is position:sticky with a z-index, so it OPENS A STACKING CONTEXT: every popover inside it -
   Waiting on us, Messages, the account menu - is trapped underneath whatever z-index `.top` itself has,
   no matter how high the popover sets its own. At 5 it lost to the deal summary strip (`.dk-sum`, 30),
   so clicking the bell on a deal drew the list behind the navy band and the first eight customers were
   simply not there. Raising `.bell-pop` cannot fix that and never could - a child cannot climb out of its
   parent's stacking context. The header is chrome: it belongs above every page layer (the highest in the
   app is `.dots .pop` at 80, and the menu's drag clone at 99) and below a full-screen dialog
   (`#people[open]`, 120), which should cover it. */
.top{height:56px;background:#fff;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;padding:0 28px;position:sticky;top:0;z-index:110}
.top h1{font-size:17px;margin:0;font-weight:600}
.user{display:flex;align-items:center;gap:10px;font-size:13px}
.avatar{width:30px;height:30px;border-radius:50%;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:12px}
.role{background:#eef3fb;color:var(--blue);padding:3px 8px;border-radius:4px;font-size:11.5px;font-weight:600}
.body{padding:24px 28px;display:flex;flex-direction:column;gap:20px}
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px}
.tile{background:#fff;border:1px solid var(--line);border-radius:8px;padding:14px 16px;display:flex;flex-direction:column;gap:6px}
.tile .l{font-size:12px;color:var(--mute);font-weight:500} .tile .v{font-size:26px;font-weight:700;letter-spacing:-.01em} .tile .d{font-size:12px;color:var(--mute)}
.up{color:var(--green)} .dn{color:var(--red)}
.card{background:#fff;border:1px solid var(--line);border-radius:8px;display:flex;flex-direction:column;min-width:0}
.ch{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--line);gap:12px;flex-wrap:wrap}
.ch h2{font-size:14px;margin:0;font-weight:600}
.cb{padding:12px 16px;display:flex;flex-direction:column;gap:10px}
.tw{overflow-x:auto}
table{border-collapse:collapse;width:100%;font-size:13px} th{text-align:left;font-size:11.5px;color:var(--mute);font-weight:600;padding:8px 12px;border-bottom:1px solid var(--line);text-transform:uppercase;letter-spacing:.04em;white-space:nowrap} td{padding:9px 12px;border-bottom:1px solid #eef0f3;vertical-align:top}
tr:target td{background:#fff7f0}
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border-radius:6px;font-size:13px;font-weight:600;border:1px solid var(--line);background:#fff;color:var(--ink);cursor:pointer;text-decoration:none;font-family:inherit}
.btn.p{background:var(--orange);border-color:var(--orange);color:#fff} .btn.b{background:var(--blue);border-color:var(--blue);color:#fff} .btn.s{padding:4px 9px;font-size:12px}
.pid{display:inline-block;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;font-weight:700;color:var(--mute);background:rgba(0,0,0,.06);border-radius:5px;padding:1px 5px;vertical-align:middle;letter-spacing:.02em}
.pill{display:inline-block;padding:2px 8px;border-radius:999px;font-size:11.5px;font-weight:600;white-space:nowrap}
.ok{background:#e6f5ec;color:var(--green)} .bad{background:#fbe7e7;color:var(--red)} .warn{background:#fcf1dc;color:var(--amber)} .info{background:#e9f0fb;color:var(--blue)} .gray{background:#eef0f3;color:var(--mute)}
/* build 272 — one more pill, for the rail that already has a colour everywhere else in HQ: the
   Messenger bubble. Added to the SET rather than written into the leads board, so the next screen that
   shows a channel wears the same one. */
.purple{background:#efeafc;color:#5b43ad}
.bar{height:8px;background:#eef0f3;border-radius:4px;overflow:hidden} .bar i{display:block;height:100%;border-radius:4px}
/* build 157 (Jon 9/15): a URL, a token or a secret NAME is one unbreakable word, and .mono had no rule
   about it, so every page that printed one had to remember — /approvals and /pricerules had patched it
   locally with word-break, /reviews /referrals /reports /automations had not, and /automations ran 248px
   off the side of a phone. `anywhere` rather than `break-word` on purpose: only `anywhere` counts in
   MIN-CONTENT sizing, which is what a grid track and a flex row measure, so break-word leaves the
   blowout below in place while looking like it fixed it. */
.mono{font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:12px;overflow-wrap:anywhere}
/* THE GRID TRACK MUST BE ALLOWED TO BE NARROWER THAN ITS CONTENT (build 157). `1fr` is shorthand for
   `minmax(auto,1fr)`, and that `auto` floor is the widest child's min-content — so ONE table or one long
   heading shoves the whole track past the screen and the page scrolls sideways. It is never the child
   that looks wrong, which is why this survived: /reviews was 102px over and /referrals 108px with nothing
   on either page visibly at fault. minmax(0,...) drops the floor; min(380px,100%) keeps the two-up
   behaviour on a real screen while letting the column collapse in a container narrower than one card. */
.two{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(380px,100%),1fr));gap:20px}
.three{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:20px} @media(max-width:1100px){.three{grid-template-columns:minmax(0,1fr)}}
.muted{color:var(--mute);font-size:12.5px}
.seg{display:inline-flex;border:1px solid var(--line);border-radius:6px;overflow:hidden;font-size:12.5px;font-weight:600} .seg a{padding:6px 12px;background:#fff;color:var(--ink);text-decoration:none} .seg a.on{background:var(--navy);color:#fff}
input,select,textarea{font:inherit;padding:7px 9px;border:1px solid var(--line);border-radius:6px;background:#fff;color:var(--ink);width:100%} textarea{min-height:80px}
input.s{padding:4px 7px;font-size:12.5px} .inl{display:flex;gap:8px;align-items:center;flex-wrap:wrap} .inl input,.inl select{width:auto}
form.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(160px,100%),1fr));gap:10px} label{font-size:12px;color:var(--mute);display:flex;flex-direction:column;gap:4px}
.flash{background:#e6f5ec;color:var(--green);padding:8px 12px;border-radius:6px;font-size:13px}
details summary{cursor:pointer;color:var(--blue);font-size:12.5px}
.note{font-size:12.5px;padding:6px 0;border-bottom:1px dashed var(--line)} .note b{color:var(--ink)}
.menu{display:none;background:none;border:0;padding:6px;margin-right:8px;color:var(--ink);cursor:pointer}
/* build 180 (Jon 9/15): the drawer and its scrim sit ABOVE every page layer - the deal summary strip is 30, popovers 70-80,
   the menu drag clone 99 - and below the header (110) so the hamburger that opened it can still close it. At 20 the
   sticky deal summary painted over the open drawer on a phone and "did not disappear". */
.scrim{display:none;position:fixed;inset:0;background:rgba(15,27,45,.45);z-index:104}
@media(max-width:900px){
 .side{position:fixed;left:0;top:0;bottom:0;z-index:105;transform:translateX(-100%);transition:transform .2s;width:250px;height:100vh}
 body.nav-open .side{transform:none} body.nav-open .scrim{display:block}
 .menu{display:inline-flex} .top{padding:0 14px;height:52px} .top h1{font-size:15px}
 /* build 218: a record's heading ("PS-1042 · 2021 Harley-Davidson Street Glide Special" + the store tag) wrapped to three
    lines on a phone and pushed the bubbles off the bar — one line, ellipsised, the whole name is on the page below */
 .top h1{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}
 /* DIRECT children only. This hides the signed-in name to save width on a phone — but without the
    `>` it also hit every <span> inside the bell popovers, which live inside .user, so the Messages
    list rendered as blank blue bars on anything under 900px. Nobody noticed because the popover is
    a click away and the bug is invisible on a desktop. (Found 9/12 adding the second bubble.) */
 .user > span:not(.role){display:none}
 .body{padding:12px;gap:12px} .tiles{grid-template-columns:repeat(2,1fr);gap:10px} .tile .v{font-size:22px}
 .three,.two{grid-template-columns:minmax(0,1fr)} .seg{flex-wrap:wrap} .seg a{padding:6px 9px} .storetag{margin-left:6px}
 /* A control carrying its own width — style="min-width:120px", a search box set to 270px — cannot shrink
    inside a flex row that wraps, so the row wraps and then overflows anyway: /chase and /scoreboard were
    each 19px over on a 360px screen from one input. max-width beats an inline width, which is the point:
    this reaches the ones written by hand in a template without going and finding them. (build 157) */
 .inl input,.inl select,.inl textarea,form.inl input,form.inl select{max-width:100%}
 table{font-size:12.5px} th,td{padding:7px 8px} form.grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)} .card{border-radius:6px}
}
@media(max-width:480px){.tiles{grid-template-columns:1fr 1fr} .inl{gap:6px}}

/* build 33: HQ ⇄ Desk workspace switch under the logo (owner + builder only) */
.wsw{margin:12px 14px 0;flex-shrink:0;display:flex;border:1px solid #2a3a56;border-radius:6px;overflow:hidden;font-size:12px;font-weight:700;letter-spacing:.04em}
.wsw a{flex:1;text-align:center;padding:6px 4px;color:#8b98ad;text-decoration:none;background:#121f35} .wsw a.on{background:var(--blue);color:#fff} .wsw a:hover:not(.on){color:#fff}
.stores{margin:14px 14px 8px;display:flex;background:#182640;border:1px solid #2a3a56;border-radius:6px;padding:3px;gap:3px}
.stores a{flex:1;text-align:center;padding:6px 4px;border-radius:4px;font-size:12.5px;font-weight:600;color:#8b98ad;text-decoration:none}
.stores a.on{background:var(--orange);color:#fff} .stores a:hover:not(.on){color:#fff;background:#1c2c48}
.storetag{margin-left:10px;font-size:11.5px;font-weight:600;color:var(--orange);background:#fff1e8;padding:3px 8px;border-radius:4px;vertical-align:middle}

.legend{display:flex;gap:14px;font-size:12px;color:var(--mute)} .legend i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:-1px}
svg .bar:hover rect{opacity:.85}

/* ---- Brainstorms + Projects (build 9) ---- */
.lanes{display:flex;gap:6px;flex-wrap:wrap} .lanes a{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border:1px solid var(--line);border-radius:999px;background:#fff;font-size:12.5px;font-weight:600;color:var(--ink);text-decoration:none}
.lanes a.on{background:var(--navy);border-color:var(--navy);color:#fff} .lanes a b{background:#eef0f3;color:var(--mute);border-radius:999px;padding:0 6px;font-size:11px} .lanes a.on b{background:#2a3a56;color:#fff}
.idea{background:#fff;border:1px solid var(--line);border-radius:8px;display:flex;gap:14px;padding:14px 16px} .idea.pin{border-color:#f7c9a8;background:#fffaf6}
.vote{display:flex;flex-direction:column;align-items:center;gap:2px;flex-shrink:0} .vote button{width:44px;height:52px;border:1px solid var(--line);border-radius:8px;background:#fff;cursor:pointer;font:inherit;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--mute);font-weight:700;font-size:15px}
.vote button.on{background:#fff1e8;border-color:var(--orange);color:var(--orange)} .vote button:disabled{cursor:default;opacity:.7} .vote button svg{width:14px;height:14px}
.idea .t{font-weight:600;font-size:14.5px;margin:0 0 2px} .idea .m{display:flex;gap:8px;flex-wrap:wrap;align-items:center;font-size:12px;color:var(--mute);margin-bottom:6px} .idea .bd{white-space:pre-wrap;font-size:13.5px} .idea .body{flex:1;min-width:0}
.idea .actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:10px} .idea .actions form{display:inline-flex;gap:6px;align-items:center} .idea .actions form.cm{flex:1 1 260px;max-width:420px;min-width:0}  /* min-width:0 or the flex item floors at min-content and overflows on a phone — build 157 */ .idea .actions form.cm input{flex:1;width:auto;min-width:120px}
.pb-src{font-size:10.5px;font-weight:600;color:#7c4dff;background:#f1ebff;border-radius:999px;padding:2px 7px;margin-left:auto;white-space:nowrap}
.st-new{background:#e9f0fb;color:var(--blue)} .st-considering{background:#fcf1dc;color:var(--amber)} .st-planned{background:#efe9ff;color:#6b3fd1} .st-done{background:#e6f5ec;color:var(--green)} .st-parked{background:#eef0f3;color:var(--mute)}
.st-active{background:#e6f5ec;color:var(--green)} .st-blocked{background:#fbe7e7;color:var(--red)}
.dep{display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:600;background:#eef0f3;color:var(--mute)}
.kanban{display:grid;grid-template-columns:repeat(5,minmax(230px,1fr));gap:12px;overflow-x:auto;align-items:start}
.kcol{background:#eef0f3;border-radius:8px;padding:8px;min-height:120px} .kcol h3{margin:2px 6px 8px;font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--mute);display:flex;justify-content:space-between}
.pc{background:#fff;border:1px solid var(--line);border-radius:6px;padding:10px 12px;margin-bottom:8px;display:block;color:var(--ink);text-decoration:none} .pc:hover{border-color:#b9c3d3;color:var(--ink)}
.pc .t{font-weight:600;font-size:13.5px;margin-bottom:4px} .pc .m{font-size:11.5px;color:var(--mute);display:flex;gap:6px;flex-wrap:wrap;align-items:center} .pc .nx{font-size:12px;margin-top:6px;color:var(--ink)} .pc .nx b{color:var(--mute);font-weight:600}
.pr1{background:#fbe7e7;color:var(--red)} .pr2{background:#fcf1dc;color:var(--amber)} .pr3{background:#eef0f3;color:var(--mute)}
.vis-private{color:#6b3fd1} .vis-leads{color:var(--blue)} .vis-team{color:var(--green)}
.dump pre{white-space:pre-wrap;font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:12px;background:#0f1b2d;color:#dfe6f0;padding:14px 16px;border-radius:8px;max-height:480px;overflow:auto;margin:0}
.dump-doc h2{font-size:18px;margin:18px 0 6px} .dump-doc h3{font-size:13px;text-transform:uppercase;letter-spacing:.05em;color:var(--mute);margin:14px 0 6px} .dump-doc li{margin:4px 0} .dump-doc .sub{color:var(--mute);font-size:12.5px;white-space:pre-wrap}
@media(max-width:900px){.kanban{display:flex;flex-direction:column;overflow:visible} .kcol{min-height:0} .kcol:empty{display:none} .idea{padding:12px} .vote button{width:38px;height:46px}}
@media print{.side,.top,.noprint{display:none!important} .body{padding:0} .main{display:block} body{background:#fff}}

/* ---- shared hero + band (lifted from sops.html so any page can use them) ---- */
.kb-hero{background:linear-gradient(135deg,#0f1b2d 0%,#17365f 55%,#1f5fbf 130%);border-radius:14px;padding:34px 30px;margin-bottom:22px;position:relative;overflow:hidden;box-shadow:0 10px 30px -12px rgba(15,27,45,.5)}
.kb-hero:before{content:"";position:absolute;right:-60px;top:-60px;width:260px;height:260px;border-radius:50%;background:radial-gradient(circle,rgba(242,106,27,.35),transparent 70%)}
.kb-hero:after{content:"";position:absolute;right:-120px;bottom:-140px;width:320px;height:320px;border-radius:50%;background:radial-gradient(circle,rgba(31,95,191,.35),transparent 70%)}
.kb-hero-in{position:relative;max-width:720px}
.kb-eyebrow{color:#f7b98e;font-size:11px;font-weight:700;letter-spacing:.18em}
.kb-h{color:#fff;font-size:28px;font-weight:700;margin:8px 0 4px;letter-spacing:-.02em}
.kb-sub{color:#c7d3e6;font-size:14px;margin:0 0 18px;max-width:560px}
.sop-band{padding:20px 22px;color:#fff;display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap}
.sop-crumb{font-size:11px;text-transform:uppercase;letter-spacing:.08em;opacity:.85}
.sop-band h2{margin:3px 0 0;font-size:20px;font-weight:700}
@media(max-width:640px){.kb-hero{padding:24px 18px}.kb-h{font-size:22px}.sop-band{padding:16px}.sop-band h2{font-size:17px}}
/* ---- Reports library + Site Change Log (build 12, 2026-09-07) ---- */
.rp-stats{display:flex;gap:10px;flex-wrap:wrap} .rp-stats div{background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.18);border-radius:10px;padding:10px 14px;min-width:92px;display:flex;flex-direction:column;gap:3px}
.rp-stats b.hot{color:#ffb38a} .rp-stats b{color:#fff;font-size:22px;font-weight:700;letter-spacing:-.02em;line-height:1} .rp-stats span{color:#b9c8dd;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em}
.rp-bar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px}
.rp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px}
.rp-card{background:#fff;border:1px solid var(--line);border-left:4px solid var(--accent,#6b7280);border-radius:8px;padding:14px 16px;display:flex;flex-direction:column;gap:7px;color:var(--ink);text-decoration:none;transition:box-shadow .15s,transform .15s}
.rp-card:hover{box-shadow:0 8px 24px -14px rgba(15,27,45,.45);transform:translateY(-1px);color:var(--ink)}
.rp-top{display:flex;gap:6px;align-items:center;flex-wrap:wrap} .rp-card .t{font-weight:600;font-size:15px;line-height:1.3} .rp-meta{font-size:12px;color:var(--mute)}
.rp-sum{font-size:13px;color:#3b4557;line-height:1.45;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.rp-foot{display:flex;justify-content:space-between;align-items:center;margin-top:auto;padding-top:6px;border-top:1px dashed var(--line)} .rp-open{font-size:12.5px;font-weight:600;color:var(--blue)}
.rp-frame{width:100%;border:0;min-height:70vh;background:#fff;border-radius:0 0 8px 8px}
.rp-detail-head{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;align-items:flex-start}
.rp-kv{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;font-size:13px} .rp-kv dt{color:var(--mute);margin:0} .rp-kv dd{margin:0}
.cl-table td{font-size:12.5px;line-height:1.4} .cl-table td.cl-change{min-width:220px;max-width:320px} .cl-table td.cl-metric,.cl-table td.cl-base{min-width:160px;max-width:240px;color:#3b4557} .cl-table td.cl-status{white-space:nowrap}
.cl-table textarea.s{min-height:54px;font-size:12.5px;padding:5px 7px} .cl-table select.s{padding:4px 7px;font-size:12px;width:auto}
.cl-st-live{background:#e6f5ec;color:var(--green)} .cl-st-pending{background:#e9f0fb;color:var(--blue)} .cl-st-hold{background:#fcf1dc;color:var(--amber)} .cl-st-rolled-back{background:#fbe7e7;color:var(--red)}
.cl-blank{color:#b45309;background:#fff7ed;border:1px dashed #fdba74;border-radius:6px;padding:4px 8px;font-size:12px;display:inline-block}
@media(max-width:900px){.rp-stats div{min-width:70px;padding:8px 10px} .rp-stats b{font-size:18px} .rp-grid{grid-template-columns:1fr}}
/* ---- stamped field history (build 13) ---- */
.stamps{display:flex;flex-direction:column;gap:3px;margin-top:6px;font-size:11.5px;color:#3b4557;line-height:1.35} .stamp{padding:3px 6px;background:#f5f6f8;border-left:2px solid #c9d1de;border-radius:0 4px 4px 0;word-break:break-word}
.stamp b{color:var(--ink)} .stamp i{color:var(--mute);font-style:normal;font-weight:600} .stamp s{color:#9aa3b2} .stamps-more summary{font-size:11px;padding:2px 0} .stamps-more{margin-top:2px}
.stamp-hint{font-size:11px;color:var(--mute);margin-top:4px}
.histrow td{background:#fbfbfc}

/* ---- Messages (build 19): the top-bar bubble + the chat page ---- */
.bell{position:relative;margin-right:4px}
.bell>button{position:relative;background:none;border:0;padding:6px;border-radius:6px;color:var(--mute);cursor:pointer;display:flex}
.bell>button:hover{background:#f1f4f8;color:var(--ink)}
.bell>button>i{position:absolute;top:-1px;right:-2px;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:var(--blue);color:#fff;font-size:10.5px;font-weight:700;font-style:normal;display:flex;align-items:center;justify-content:center;line-height:1}
.bell>button>i.hot{background:var(--orange)}
.bell>button>i[hidden]{display:none}   /* display:flex above beats the browser's [hidden] rule — without this you get an empty "0" bubble forever */
.bell-pop{position:absolute;right:0;top:38px;width:330px;max-width:calc(100vw - 24px);background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 16px 40px -12px rgba(15,27,45,.4);z-index:30;overflow:hidden}
.bell-h{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;border-bottom:1px solid var(--line);font-size:13px} .bell-h a{font-size:12px}
.bell-i{display:block;padding:9px 12px;border-bottom:1px solid #eef0f3;text-decoration:none;color:var(--ink)} .bell-i:hover{background:#f7f9fc;color:var(--ink)}
.bell-i.un{background:#f4f8ff} .bell-i.un:hover{background:#eaf1fd}
.bell-t{display:block;font-size:13px;font-weight:600} .bell-t b{background:var(--blue);color:#fff;border-radius:999px;padding:0 6px;font-size:10.5px;vertical-align:1px}
.bell-at{font-style:normal;font-size:10.5px;font-weight:700;color:var(--orange);background:#fff1e8;border-radius:4px;padding:1px 5px}
.bell-p{display:block;font-size:12px;color:var(--mute);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bell-w{display:block;font-size:11px;color:#9aa3b2;margin-top:2px}
/* build 233.1 — the card wrapper is BACK, because the small x is back on every card (Jon 9/17). A
   <button> cannot live inside the card's <a>: interactive content nested in a link is dropped or
   re-parented by the browser, the same family as a <form> in a <form>. So the card is a flex wrapper
   and the two are siblings, with the border moved onto the wrapper so the list looks unchanged.
   `min-width:0` is load-bearing — without it the flex item refuses to shrink and .bell-p's ellipsis
   never fires, which is how a long first message pushes the x off the popover.
   The x is 26px wide and full height: a tap target on a phone, and far enough from the card's own link
   that clearing and opening are not the same gesture.
   .bell-row.gone is the struck-through state after a successful clear — the card stays put until the
   next poll so the manager can see WHICH one went, rather than the list silently reflowing. */
.bell-row{display:flex;align-items:stretch;border-bottom:1px solid #eef0f3}
.bell-row:hover{background:#f7f9fc} .bell-row .bell-i{flex:1;min-width:0;border-bottom:0}
.bell-row.un{background:#f4f8ff} .bell-row.un:hover{background:#eaf1fd}
.bell-row.gone{opacity:.4} .bell-row.gone .bell-t{text-decoration:line-through}
.bell-x{flex:0 0 auto;width:26px;background:none;border:0;border-left:1px solid #eef0f3;padding:0;
        color:#b6bdc9;font-size:16px;line-height:1;cursor:pointer}
.bell-x:hover{background:#fdecec;color:#c0392b} .bell-x:disabled{opacity:.45;cursor:default}

/* build 233 — Clear all in the dropdown header, and "Open all" as the foot of the list.
   The header button is styled as a quiet action, not a primary one — it is destructive-ish and sits
   above a list somebody is reading, so it must not be the loudest thing in the popover. It clears the
   WHOLE list; the per-card x above clears one. */
.bell-clear{background:none;border:1px solid var(--line);border-radius:5px;padding:2px 8px;font-size:11px;
            font-weight:700;color:var(--mute);cursor:pointer;letter-spacing:.02em}
.bell-clear:hover{background:#fdecec;border-color:#f0c2c2;color:#c0392b}
.bell-clear:disabled{opacity:.5;cursor:default} .bell-clear[hidden]{display:none}
/* The foot. A block link so the whole strip is the target on a phone, and visually separated from the
   rows above it so it does not read as one more customer. */
.bell-f{display:block;padding:9px 12px;border-top:1px solid var(--line);background:#f7f9fc;
        font-size:12px;font-weight:600;text-align:center;text-decoration:none;color:var(--blue)}
.bell-f:hover{background:#eaf1fd} .bell-f[hidden]{display:none}

.msg-wrap{display:grid;grid-template-columns:280px 1fr;gap:16px;align-items:start}
.msg-rail{background:#fff;border:1px solid var(--line);border-radius:8px;overflow:hidden;position:sticky;top:76px;max-height:calc(100vh - 96px);overflow-y:auto}
.msg-rail-top{display:flex;justify-content:space-between;align-items:center;padding:11px 12px;border-bottom:1px solid var(--line);font-size:13px}
.msg-th{display:flex;gap:10px;align-items:center;padding:10px 12px;border-bottom:1px solid #eef0f3;text-decoration:none;color:var(--ink)}
.msg-th:hover{background:#f7f9fc;color:var(--ink)} .msg-th.on{background:#f4f8ff;box-shadow:inset 3px 0 0 var(--orange)}
.msg-th-b{min-width:0;flex:1} .msg-th-t{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.msg-th-p{font-size:11.5px;color:var(--mute);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.msg-n{background:var(--blue);color:#fff;border-radius:999px;padding:1px 7px;font-size:11px;font-weight:700;flex-shrink:0} .msg-n.mn-hot{background:var(--orange)}
.msg-av{width:30px;height:30px;border-radius:50%;background:#e5ebf5;color:#43536e;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:11.5px;flex-shrink:0}
.msg-av.gen{background:var(--navy);color:#fff}
.msg-main{min-width:0}
.msg-feed{padding:14px 16px;display:flex;flex-direction:column;gap:12px;max-height:calc(100vh - 300px);min-height:280px;overflow-y:auto}
.msg-day{text-align:center;font-size:11px;color:var(--mute);border-bottom:1px solid var(--line);line-height:0;margin:6px 0} .msg-day span{background:#fff;padding:0 10px}
.msg-day.new{border-color:var(--orange)} .msg-day.new span{color:var(--orange);font-weight:700;text-transform:uppercase;letter-spacing:.08em}
.msg-row{display:flex;gap:10px} .msg-row.tagged .msg-t{background:#fff8f2;border-color:#f7c9a8}
.msg-b{min-width:0;flex:1} .msg-h{display:flex;gap:8px;align-items:baseline;font-size:12.5px} .msg-h b{font-size:13px}
.msg-t{background:#f5f6f8;border:1px solid transparent;border-radius:8px;padding:8px 11px;margin-top:3px;font-size:13.5px;line-height:1.45;white-space:pre-wrap;word-break:break-word}
.msg-row.me .msg-av{background:var(--blue);color:#fff} .msg-row.me .msg-t{background:#eef3fb}
.mn{background:#e9f0fb;color:var(--blue);border-radius:4px;padding:1px 4px;font-weight:600} .mn.me{background:#fff1e8;color:var(--orange)}
.msg-compose{border-top:1px solid var(--line);padding:12px 16px;display:flex;flex-direction:column;gap:8px}
.msg-box{position:relative} .msg-box textarea{min-height:66px;resize:vertical}
.msg-send{display:flex;justify-content:space-between;align-items:center;gap:10px}
.msg-ac{position:absolute;left:0;bottom:calc(100% + 4px);width:min(420px,100%);background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 14px 34px -12px rgba(15,27,45,.4);z-index:12;overflow:hidden}
.msg-ac-i{display:flex;gap:8px;align-items:center;padding:7px 10px;font-size:13px;cursor:pointer} .msg-ac-i.on{background:#f4f8ff}
.msg-ac-i .msg-av{width:24px;height:24px;font-size:10px} .msg-ac-i .muted{margin-left:auto;font-size:11.5px}
.msg-dlg{border:0;border-radius:10px;padding:0;width:min(520px,94vw);box-shadow:0 24px 60px -18px rgba(15,27,45,.5)} .msg-dlg::backdrop{background:rgba(15,27,45,.45)}
.msg-people{max-height:240px;overflow-y:auto;border:1px solid var(--line);border-radius:6px}
.msg-p{flex-direction:row;align-items:center;gap:9px;padding:7px 10px;border-bottom:1px solid #eef0f3;font-size:13px;color:var(--ink);cursor:pointer} .msg-p:hover{background:#f7f9fc}
.msg-p input{width:auto} .msg-p .msg-av{width:26px;height:26px;font-size:10.5px}
@media(max-width:900px){
 .msg-wrap{grid-template-columns:1fr} .msg-rail{position:static;max-height:none;order:2} .msg-main{order:1}
 .msg-feed{max-height:none;min-height:0} .bell-pop{position:fixed;right:10px;top:56px}
}

/* ---- Messages build 20: rail sections, department channels, group management ---- */
.msg-rail-h{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--mute);font-weight:700;padding:12px 12px 5px;background:#fafbfc;border-bottom:1px solid #eef0f3;border-top:1px solid #eef0f3}
.msg-join{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 12px;border-bottom:1px solid #eef0f3;font-size:12.5px}
.msg-join span{color:var(--mute);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.msg-main .ch h2{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.msg-dlg .msg-p form{margin-left:auto}
/* The hidden ATTRIBUTE has to beat our own display rules. .btn is inline-flex and .bell i is flex, so
   both rendered anyway when marked hidden — an empty "0" badge, then a push button that shouldn't show.
   One global rule instead of chasing it per component. (Jon 9/8) */
[hidden]{display:none!important}
/* build 21.6: a message you just sent, before the server has confirmed it */
.msg-row.pending .msg-t{opacity:.6}
.msg-row.failed .msg-t{background:#fbe7e7;border-color:#f3c2c2}
.msg-row.failed .msg-h .muted{color:var(--red);font-weight:600}

/* ---- Message reactions (build 21.8) ---- */
.msg-rx{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
.msg-rx:empty{display:none}
.rx{display:inline-flex;align-items:center;gap:4px;padding:1px 7px;border:1px solid var(--line);border-radius:999px;background:#fff;cursor:pointer;font:inherit;font-size:13px;line-height:1.5}
.rx b{font-size:11.5px;font-weight:700;color:var(--mute)}
.rx:hover{border-color:#b9c3d3}
.rx.mine{background:#eef3fb;border-color:#9dbdea} .rx.mine b{color:var(--blue)}
/* max-width, because the 8-column grid measures ~319px and would hang off a 320px phone */
.rx-pick{position:fixed;z-index:40;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:0 16px 40px -12px rgba(15,27,45,.45);padding:7px;max-width:calc(100vw - 16px)}
.rx-quick,.rx-all{display:grid;grid-template-columns:repeat(8,1fr);gap:2px}
.rx-quick{padding-bottom:5px;margin-bottom:5px;border-bottom:1px solid var(--line)}
.rx-pick button{border:0;background:none;cursor:pointer;font-size:19px;line-height:1;padding:5px;border-radius:6px;min-width:0}
.rx-pick button:hover{background:#eef3fb}
/* touch: no hover, so the add-reaction button has to be permanently visible */


/* ---- Reaction affordance (build 23.3). Build 21.8 put every reaction behind one faint "☺+" at
   opacity 0 that only appeared on row hover and then opened a picker. It worked and nobody found it.
   Now: a Slack-style toolbar on the message with the four common emoji clickable in ONE click, plus
   a ＋ for the rest, and once a message has pills a permanently visible ＋ sits beside them. ---- */
.msg-row{position:relative}
.msg-tools{position:absolute;top:-9px;right:6px;display:flex;gap:1px;padding:2px;background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 3px 10px -3px rgba(15,27,45,.28);opacity:0;transition:opacity .1s;z-index:3}
.msg-row:hover .msg-tools,.msg-tools:focus-within{opacity:1}
.msg-tools button{border:0;background:none;cursor:pointer;font:inherit;font-size:16px;line-height:1;padding:3px 4px;border-radius:5px}
.msg-tools button:hover{background:#eef3fb;transform:scale(1.15)}
.msg-tools .msg-addrx{font-size:14px;color:var(--mute);padding:3px 5px}
.msg-tools .msg-addrx:hover{color:var(--blue)}
.rx-more{color:var(--mute);font-size:12px;padding:1px 8px}
/* Touch has no hover, so the toolbar has to be there without one. */
@media(hover:none){.msg-tools{opacity:1;position:static;margin-top:5px;box-shadow:none;width:max-content}
 /* the toolbar already carries a ＋ on touch, so the one beside the pills is noise */
 .rx-more{display:none}}
@media(max-width:900px){.msg-tools{top:-8px;right:2px}}

/* build 54 - talk-to-text mic on every textarea (static/dictate.js) */
.micbtn{flex:0 0 auto;align-self:flex-end;width:40px;height:40px;border-radius:50%;border:1px solid var(--line);background:#fff;color:var(--mute);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;padding:0;transition:color .15s,border-color .15s}
.micbtn:hover{color:var(--blue);border-color:var(--blue)}
.micbtn.on{background:#d33d3d;border-color:#d33d3d;color:#fff;animation:micpulse 1.4s infinite}
.micbtn.inline{width:32px;height:32px;margin:4px 0 0 4px;vertical-align:top}
@keyframes micpulse{0%,100%{box-shadow:0 0 0 0 rgba(211,61,61,.5)}70%{box-shadow:0 0 0 8px rgba(211,61,61,0)}}

/* ═══ build 76 — HQ on a phone ═════════════════════════════════════════════════════════════════
   Tyler and Jon both work off phones on the lot, and the CRM was the page that showed how little
   of HQ had ever been opened on one. Three things were wrong, and none of them were the sidebar
   (which has worked since build 1):

     1. A LIST IS A TABLE, AND A TABLE DOES NOT FIT. /desk/deals lays out 890px wide inside a
        375px phone. The columns that fall off the right edge are the money — so the page a
        manager checks on the way to lunch showed him the deal number and nothing else. Fixed by
        static/phone.js: it MEASURES each .tw table and only the ones that overflow become cards.
     2. iOS ZOOMS ON ANY CONTROL UNDER 16px. Every input in HQ was 12.5–14px, so tapping the
        search box on Customers threw the whole layout sideways and you had to pinch back out to
        read the result. That is most of what "all over the place" was.
     3. A 24px BUTTON IS NOT A TAP TARGET. .btn.s is the right size for a mouse and wrong for a
        thumb, and Claim / Log it / Set are all .btn.s.
   700px, not 900px, on purpose: 900 is where the sidebar collapses — a tablet in landscape has
   the room for a table and should keep it. ═══════════════════════════════════════════════════ */
@media(max-width:700px){
 /* 1 — the table, as cards. phone.js adds .m-stack only when the table really overflows, and
    copies the header text onto each cell as data-l. Two columns of label-over-value, so a card
    is short enough to read without scrolling and a 13-column table is 7 lines instead of 13. */
    Every selector is a > chain down from .m-stack on purpose: a table nested inside a cell is
    somebody else's layout and must not be turned into cards by a rule meant for its parent. */
 .tw.m-stack{overflow-x:visible}
 .m-stack>table{display:block;width:100%}
 .m-stack>table>thead,.m-stack>table>tbody{display:block;width:100%}
 .m-stack>table>*>tr.m-hr{display:none}         /* the header row IS the labels now */
 .m-stack>table>*>tr{display:grid;grid-template-columns:1fr 1fr;gap:0 10px;align-items:start;
  background:#fff;border:1px solid var(--line);border-radius:8px;margin:0 0 8px;padding:8px 0}
 .m-stack>table>*>tr:last-child{margin-bottom:0}
 .m-stack>table>*>tr.m-sub{display:block;background:none;border:0;margin:14px 0 4px;padding:0}
 .m-stack>table>*>tr.m-sub>th{border:0;padding:0}
 .m-stack>table>*>tr>td{display:block;border:0;padding:4px 12px;font-size:13px;min-width:0;overflow-wrap:anywhere}
 .m-stack>table>*>tr>td[data-l]:before{content:attr(data-l);display:block;color:var(--mute);font-size:10px;
  font-weight:600;letter-spacing:.05em;text-transform:uppercase;line-height:1.6}
 .m-stack>table>*>tr>td.money{text-align:left}  /* right-aligned money in a card looks like a mistake */
 /* the hints a <th> can carry — see phone.js */
 .m-stack>table>*>tr>td[data-m=head],
 .m-stack>table>*>tr>td[data-m=wide],
 .m-stack>table>*>tr>td[data-m=full]{grid-column:1/-1}
 /* order:-1 so the card leads with who it is about whatever column the table puts first — on Deals
    the first column is the deal number, which is how the DMS thinks about a deal and not how a
    manager reading his phone does. */
 .m-stack>table>*>tr>td[data-m=head]{order:-1;font-size:15.5px;padding-bottom:5px}
 .m-stack>table>*>tr>td[data-m=head] a{display:inline-block;padding:6px 0}   /* a thumb, not a cursor */
 .m-stack>table>*>tr>td[data-m=head]:before,
 .m-stack>table>*>tr>td[data-m=full]:before{display:none}
 .m-stack>table>*>tr>td[data-m=full]{padding:6px 12px}
 .m-stack>table>*>tr>td[data-m=hide]{display:none}

 /* 2 — 16px or iOS zooms. This is a phone-only rule: the desktop keeps its dense 12.5px. */
 input,select,textarea,button,.btn,.btn.s,input.s,.dk-struct input,.dk-lines input{font-size:16px}
 /* 3 — thumbs. 40px is the floor everybody's guidelines agree on. */
 .btn{min-height:40px;padding:9px 14px} .btn.s{min-height:38px;padding:8px 13px}
 .seg a{padding:10px 14px}
 input,select,textarea{padding:9px 11px} input.s{padding:8px 10px}
 /* desk_base.html keeps its layout classes in a <style> INSIDE the body, and a body <style> beats a
    <head> stylesheet at equal specificity — so the three rules below lost silently on exactly the
    pages that prompted this build: the CRM's stage chips stayed 27px tall. A leading `body` is the
    cheapest thing that outranks it, and it is here rather than in desk_base because it is the same
    phone rule the rest of HQ gets. (Jon 9/12) */
 body .dk-chips a{padding:9px 14px;font-size:13px}
 body .dk-tabs a{padding:11px 14px}
 body .dk-struct input,body .dk-lines input{font-size:16px}
 body .dk-id .kv{flex-wrap:wrap}

 /* long values — an email, a URL, a 60-character unit description — must wrap, not push the page */
 td,.dk-id .kv b,.note,.stamp{overflow-wrap:anywhere}
 /* The toolbar over every list. Thumb-sized buttons do not fit beside a search box on a phone, so
    the search form takes its own line and the filter buttons take the next one — rather than the
    four half-empty lines you get from letting flex-wrap sort it out. */
 /* !important only because the list pages carry style="flex:1" on that form inline, and nothing in a
    stylesheet outranks an inline style. The alternative was editing the same attribute in a dozen
    templates and hoping the next list page remembers. */
 .dk-bar>form.dk-bar{flex:1 0 100%!important}
 .dk-bar>form.dk-bar input[type=search]{max-width:none}
 /* nowrap is right for "Found: 12" and wrong for the sentence /desk/settings puts here, which cannot
    wrap and so ran 40px off a phone. Full width already, so let it run to two lines. (build 157) */
 body .dk-found{margin-left:0;flex:1 0 100%;white-space:normal}
}
/* The top bar wants 422px before it starts wrapping — menu + title + storetag + three bells + the role
   pill + the avatar — so on a 375px phone the page title broke onto a second line and the header ate
   two rows of a screen that has eleven. The name already hides at 900; the role pill goes here for the
   same reason, since the sidebar and the avatar both say who you are. (build 76) */
@media(max-width:480px){
 /* No ellipsis on the title: the storetag lives inside the h1 and WHICH STORE you are looking at is
    not a detail two stores can afford to have clipped. Reclaiming the pill's 51px is enough. */
 .top{padding:0 12px;gap:8px} .top h1{min-width:0}
 .top .role{display:none} .user{gap:6px}
 .storetag{margin-left:6px;padding:2px 6px}
}

/* build 114 — what the VIN decoder says, under the field it belongs to. Muted by default because it is
   advisory: a decode never blocks a save, so it must not read like an error. */
.vin-note{font-size:11.5px;line-height:1.35;margin:3px 0 0;color:var(--mute)}
.vin-note[data-kind="ok"]{color:#2e7d4f}
.vin-note[data-kind="bad"]{color:#d33d3d}
.vin-note[data-kind="warn"]{color:#9a6b00}
.vin-note[data-kind="busy"]{opacity:.7;font-style:italic}
@media(max-width:700px){.vin-note{font-size:12.5px}}

/* ═══ THE LANE BAR (build 149) ══════════════════════════════════════════════════════════════════
   The row of boxes under the pipeline on /desk/leads and over the book on /desk/crm: Hands raised,
   Nobody answered, Not started, Messenger. ONE definition, here rather than in either page's <style>,
   because it is the same question on both pages — "which list am I on" — and a rep who learns the
   control on Leads has to recognise it on Customers.

   `body ` prefixes every selector for the reason CLAUDE.md gives: a Desk page keeps its layout in a
   <style> inside the body, and at equal specificity the LATER rule wins, so an unprefixed rule here
   loses silently on exactly the pages it is written for.

   Why Messenger is a box and not a second table (Jon 9/15): it is most of the volume, most of it
   arrives with no phone and no email, and until now a rep scrolled past all of it to reach the leads
   they actually work. One lane shows at a time; the box says how many are behind it. */
body .pipe-sub{display:flex;gap:8px;flex-wrap:wrap;padding:0 8px 12px;border-bottom:1px solid var(--line);margin-bottom:10px}
body .pipe-s{display:flex;align-items:baseline;gap:6px;text-decoration:none;color:var(--ink);border:1px solid var(--line);border-radius:999px;padding:5px 12px;font-size:12px}
body .pipe-s b{font-size:14px;font-variant-numeric:tabular-nums} body .pipe-s span{color:var(--mute)}
body .pipe-s.on{background:var(--navy);border-color:var(--navy);color:#fff} body .pipe-s.on span{color:#cfd9e6}
body .pipe-s.off{opacity:.65;cursor:default}
/* The Messenger box sits at the far end of the bar because it is the OTHER board, not another filter
   on this one, and it is blue like the lane header it opens. The waiting count rides inside it in red:
   it is the reason to open the box, and the only number on the bar that says somebody is owed
   something. */
/* Pushed to the far end only when it IS the far end. On Leads the Messenger box is the last in the bar
   and the gap is what says "the other board"; on Customers it sits between Customers and Everyone, where
   an auto margin would shove Everyone out with it and open a hole in the middle of three lanes. */
body .pipe-s.msgr:last-child{margin-left:auto} body .pipe-s.msgr b{color:var(--blue)}
body .pipe-s.msgr.on{background:var(--blue);border-color:var(--blue)} body .pipe-s.msgr.on b{color:#fff}
/* build 160 — the Hot box. Red, and it is the same red the board already uses for an unanswered lead,
   because it means the same thing: this is the one to pick up the phone about. It sits after Messenger
   rather than at the far end, so `margin-left:auto` moves to whichever of the two is last and the bar
   keeps its one gap. The warm count rides inside it the way Messenger's waiting count does. */
body .pipe-s.hot:last-child{margin-left:auto} body .pipe-s.hot b{color:#c0392b}
body .pipe-s.hot.on{background:#c0392b;border-color:#c0392b} body .pipe-s.hot.on b{color:#fff}
body .pipe-s.hot.on span{color:#f6d9d4}
body .pipe-s i{font-style:normal;font-size:10.5px;font-weight:700;background:#fdecea;color:#c0392b;
 border-radius:999px;padding:2px 7px;margin-left:2px}
body .pipe-s.on i{background:rgba(255,255,255,.22);color:#fff}
/* The way out of a lane, on the lane's own header — one tap, and it says how many are on the other
   side. A lane you can only leave by scrolling back up to the bar is a lane people stop opening. */
body .lane-go{margin-left:auto;font-size:12px;text-decoration:none;color:var(--blue);white-space:nowrap}
body .lane-go:hover{text-decoration:underline}
@media(max-width:700px){
 /* The bar wraps on a phone, and margin-left:auto on a wrapped line strands the box alone on its own
    row with a hole beside it. Let it sit with the others. */
 body .pipe-s.msgr:last-child{margin-left:0} body .pipe-s.hot:last-child{margin-left:0}
 body .lane-go{margin-left:0;flex:1 1 100%}
 /* A box is a TAP TARGET here, not a chip beside a mouse — build 76's third lesson. This is a link
    rather than a form control, so the 16px zoom rule does not apply; the padding is what matters. */
 body .pipe-s{padding:8px 14px;font-size:13px} body .pipe-s b{font-size:15px}
}

/* ---------------------------------------------------------------- the report shell (build 153.2)
   Every list in HQ is a report: a toolbar with a search box, a sort and a Found count; one row of chips;
   the table; a footer of totals. It was written for the Desk (DealerCenter's shape) and lived in
   desk_base.html's body block, which meant /pricing could not use it without a third copy of the same
   twelve rules. Moved here whole so there is ONE definition. Desk pages are unchanged: these are the
   same rules, and desk_base's own block still loads after this and still wins at equal specificity. */
/* report shell */
.dk-list{display:flex;flex-direction:column;gap:10px}
.dk-bar{display:flex;gap:8px;align-items:center;flex-wrap:wrap} .dk-bar input[type=search]{flex:1;min-width:160px;max-width:360px}
/* The global input,select,textarea rule sets width:100%, and .dk-bar had an escape hatch for the
   search box but not for the sort select — so the select ate the whole bar and pushed Run, Found and
   the view toggle onto their own lines. It was there on /desk/units too and nobody had noticed,
   because that select's options are short enough to look deliberate. (Jon 9/15, build 153.2) */
.dk-bar select{width:auto;flex:0 0 auto;max-width:230px}
.m-chipmore{align-self:flex-start;margin-top:2px}
.dk-chips{display:flex;gap:6px;flex-wrap:wrap} .dk-chips a{padding:5px 11px;border-radius:999px;border:1px solid var(--line);background:#fff;font-size:12px;font-weight:600;color:var(--ink);text-decoration:none;white-space:nowrap}
.dk-chips a.on{background:var(--navy);color:#fff;border-color:var(--navy)}
.dk-found{font-size:12px;color:var(--mute);margin-left:auto;white-space:nowrap}
.dk-foot{display:flex;gap:18px;flex-wrap:wrap;padding:10px 14px;background:#f6f7f9;border-top:1px solid var(--line);font-size:12.5px;border-radius:0 0 8px 8px}
.dk-foot b{display:block;font-size:15px} .dk-foot span{color:var(--mute);font-size:11px;text-transform:uppercase;letter-spacing:.05em}
/* build 226 — THE CUSTOMER'S FACE, one rule for every list that draws one (_face.html). It lived in
   _crm_book.html's own <style> after 242, which is a block that only renders on the book lane — so the
   leads board could not have used it without a second copy, and a second copy of a control is how two
   screens stop looking like one product. The trap CLAUDE.md names is the reverse (a body <style>
   beating app.css), so the book's copy was DELETED rather than left to outrank this.
   The photo is laid OVER the initials, not instead of them: a Messenger CDN url that has expired —
   most of them do — falls back to the letters rather than to a broken-image icon. */
.who{display:flex;align-items:center;gap:9px;min-width:0}
.who-av{position:relative;overflow:hidden;border-radius:50%;flex:0 0 auto;display:inline-flex;align-items:center;
 justify-content:center;color:#fff;font-weight:700;letter-spacing:.02em;line-height:1}
.who-av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:50%}
.who-m{min-width:0;display:flex;flex-direction:column;gap:1px}
.who-s{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.money{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap} .neg{color:var(--red)} .pos{color:var(--green)}
.dk-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:10px}
.dk-card{background:#fff;border:1px solid var(--line);border-radius:8px;overflow:hidden;text-decoration:none;color:var(--ink);display:flex;flex-direction:column}
.dk-card img{width:100%;aspect-ratio:4/3;object-fit:cover;background:#eef0f3} .dk-card .noimg{aspect-ratio:4/3;background:#eef0f3;display:flex;align-items:center;justify-content:center;color:var(--mute);font-size:12px}
.dk-card .in{padding:10px 12px;display:flex;flex-direction:column;gap:4px} .dk-card b{font-size:13.5px} .dk-card .r{display:flex;justify-content:space-between;font-size:12px;color:var(--mute)}

/* ---- Deal Desk home (build 193, Jon 9/16): Tekion's deals list with the Sales Board's tiles on top --------------
   .dk-board is a scoped COPY of board.css's tile grammar (.btile: label / number / pace / hint, a status colour on
   the top edge) in the board's own palette. board.css is not loaded on the Desk on purpose: it carries unscoped
   .chip, .note, .good and .badge rules that would restyle the page under it. A change to how a tile looks is
   made in both places or in neither. */
.dk-board{--bline:#1f4a7c;--bmute:#a9c4e4;--bdim:#6f8fb5;--borange:#f5821f;background:#0b1d33;border-radius:10px;padding:10px;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:6px;color:#fff}
.dk-board .bt{background:linear-gradient(180deg,#123b6b 0%,#0f2a4a 100%);border:1px solid var(--bline);border-top:3px solid var(--bdim);border-radius:6px;padding:8px 10px;min-height:84px;display:flex;flex-direction:column;gap:3px;min-width:0;color:#fff;text-decoration:none}
a.bt:hover{border-color:var(--borange);border-top-color:var(--borange)}
.dk-board .bt.ok{border-top-color:#2ecc71} .dk-board .bt.warn{border-top-color:#f2b134} .dk-board .bt.bad{border-top-color:#ef5350} .dk-board .bt.wide{grid-column:span 2}
.dk-board .bl{font-size:11.5px;line-height:1.25;color:var(--bmute);font-weight:500}
.dk-board .bv{font-family:"Barlow Condensed","Arial Narrow",Arial,sans-serif;font-weight:700;font-size:28px;line-height:1;font-variant-numeric:tabular-nums;color:var(--borange);letter-spacing:.01em;white-space:nowrap}
.dk-board .tpace{font-size:11px;color:var(--bmute);font-variant-numeric:tabular-nums} .dk-board .tpace b{color:var(--borange);font-weight:700}
.dk-board .bh{font-size:10.5px;color:var(--bdim);line-height:1.3;font-variant-numeric:tabular-nums;margin-top:auto} .dk-board .bh a,.dk-board .bh b{color:var(--bmute)}
@media(max-width:700px){.dk-board{grid-template-columns:repeat(2,minmax(0,1fr))} .dk-board .bt.work{grid-column:span 2} .dk-board .bv{font-size:24px}}
/* Work these (build 193.3): the tile opens this card; shut by default so the deals grid stays where it was */
.dk-work>summary{cursor:pointer;list-style:none} .dk-work>summary::-webkit-details-marker{display:none} .dk-work>summary h2:before{content:"\203a";display:inline-block;margin-right:8px;transition:transform .12s} .dk-work[open]>summary h2:before{transform:rotate(90deg)}
.dk-work .dk-said{white-space:normal;max-width:460px;color:var(--ink)} .dk-work .dk-acts{white-space:nowrap} .dk-work .dk-acts .btn{margin-right:4px}
/* the list's header: its name on the left, Start deal on the right — Tekion's one primary button (TKN-F-070) */
.dk-homehd{gap:10px;flex-wrap:wrap} .dk-start{display:flex;gap:6px;align-items:center;flex:1 1 320px;justify-content:flex-end} .dk-start input[type=search]{flex:1;min-width:160px;max-width:360px} .dk-start select{width:auto}
/* the filter row: search · Filter (n) · Sort · the Status chips · Reset · count · Export */
.dk-filt{display:flex;gap:8px;align-items:center;flex-wrap:wrap;padding:0 14px 8px} .dk-filt input[type=search]{flex:1 1 200px;min-width:160px;max-width:340px}
.dk-filt .dk-status label{cursor:pointer;user-select:none} .dk-filt .dk-status input{display:none}
body .dk-chips label{padding:5px 11px;border-radius:999px;border:1px solid var(--line);background:#fff;font-size:12px;font-weight:600;color:var(--ink);white-space:nowrap} body .dk-chips label.on{background:var(--navy);color:#fff;border-color:var(--navy)}
.dk-drop{position:relative} .dk-drop>summary{list-style:none;cursor:pointer;padding:5px 11px;border-radius:999px;border:1px solid var(--line);background:#fff;font-size:12px;font-weight:600;white-space:nowrap} .dk-drop>summary::-webkit-details-marker{display:none}
.dk-drop.on>summary{border-color:var(--navy)} .dk-drop .n{font-style:normal;display:inline-block;min-width:16px;text-align:center;background:var(--navy);color:#fff;border-radius:999px;font-size:10px;padding:1px 5px;margin-left:2px}
.dk-drop .pop{position:absolute;top:calc(100% + 6px);left:0;z-index:60;width:min(360px,90vw);background:#fff;border-radius:10px;box-shadow:0 14px 40px rgba(15,27,45,.22);padding:12px 14px;display:flex;flex-direction:column;gap:8px;font-size:12.5px}
.dk-drop .pop>label{font-size:11.5px;font-weight:600;display:flex;flex-direction:column;gap:3px} .dk-drop .pop select{width:100%}
.dk-checks{display:grid;grid-template-columns:1fr 1fr;gap:4px 10px} .dk-checks label{font-weight:500;font-size:12px;display:flex;flex-direction:row;gap:6px;align-items:center} .dk-checks input{width:auto}
.dk-drop .pop .dk-cust{display:flex;gap:8px} .dk-drop .pop .dk-cust>label{flex:1;min-width:0;font-size:11.5px;font-weight:600;display:flex;flex-direction:column;gap:3px} .dk-drop .pop .dk-cust input{width:100%}
.dk-drop .pop .dk-cust[hidden]{display:none}   /* build 227: [hidden] loses to display:flex without this */
.rp-note{font-size:11.5px;color:var(--mute);margin-top:5px;max-width:78ch;line-height:1.45}
.rp-when{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap;padding:0 14px 12px}
.rp-when>label{font-size:11.5px;font-weight:600;display:flex;flex-direction:column;gap:3px}
.rp-when .dk-cust{display:flex;align-items:flex-end;gap:8px}
.rp-when .dk-cust>label{font-size:11.5px;font-weight:600;display:flex;flex-direction:column;gap:3px}
.rp-when .dk-cust[hidden]{display:none}   /* build 229: [hidden] loses to display:flex without this */
.rp-when>.btn{margin-left:auto}
@media(max-width:700px){.rp-when{gap:8px} .rp-when>label,.rp-when .dk-cust{width:100%} .rp-when .dk-cust>label{flex:1;min-width:0} .rp-when>.btn{margin-left:0}}
.dk-drop .acts{display:flex;gap:6px;justify-content:flex-end}
.dk-sort{display:flex;flex-direction:row;gap:4px;align-items:center;font-size:12px;color:var(--mute);font-weight:600;white-space:nowrap} .dk-sort select{width:auto}
.dk-reset{font-size:12px;white-space:nowrap}
/* the grid: every header sorts, the arrow marks the one in charge */
.dk-home th a{color:var(--mute);text-decoration:none;white-space:nowrap} .dk-home th a.on{color:var(--ink)} .dk-home th a i{font-style:normal;margin-left:3px}
.dk-notecol{width:44px} .dk-home td a b{white-space:nowrap}
/* a pop-over is invisible until the script has placed it: details fires toggle a frame after it opens, and that frame would draw the box at 0,0 */
.dk-note .pop:not(.placed),.dk-more .pop:not(.placed){visibility:hidden}
.dk-note>summary,.dk-more>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:3px;color:var(--mute);padding:2px 5px;border-radius:6px}
.dk-note>summary::-webkit-details-marker,.dk-more>summary::-webkit-details-marker{display:none} .dk-note>summary:hover,.dk-more>summary:hover{background:#eef0f3;color:var(--ink)}
.dk-note>summary svg{width:16px;height:16px} .dk-note>summary .n{font-size:10.5px;background:var(--blue);color:#fff;border-radius:999px;padding:0 5px;min-width:16px;text-align:center;line-height:16px}
/* the pop-overs are FIXED and placed by script when they open: .tw scrolls sideways, and an absolutely positioned
   box inside a scrolling box is clipped at its edge. */
.dk-note .pop,.dk-more .pop{position:fixed;top:0;left:0;z-index:60;background:#fff;border-radius:10px;box-shadow:0 14px 40px rgba(15,27,45,.22);padding:10px 12px;font-size:12.5px;color:var(--ink);text-align:left}
.dk-note .pop{width:min(380px,92vw);display:flex;flex-direction:column;gap:8px} .dk-note .hd{display:flex;gap:8px;align-items:baseline} .dk-note .hd a{margin-left:auto;font-size:11.5px;white-space:nowrap}
.dk-note .thread{display:flex;flex-direction:column;gap:6px;max-height:220px;overflow:auto} .dk-note .e{white-space:pre-wrap;word-break:break-word} .dk-note .e span{display:block;font-size:10.5px;color:var(--mute)}
.dk-note form.add{display:flex;gap:6px} .dk-note form.add input{flex:1}
.dk-more .pop{display:flex;flex-direction:column;gap:2px;min-width:170px} .dk-more .pop a{padding:5px 8px;border-radius:6px;text-decoration:none;color:var(--ink);white-space:nowrap} .dk-more .pop a:hover{background:#eef0f3}
.dk-more>summary{font-weight:700;letter-spacing:1px}
.dk-assign{font-size:11.5px;font-weight:600;color:var(--blue);border:1px dashed var(--blue);border-radius:999px;padding:1px 8px;text-decoration:none;white-space:nowrap}
.dk-chat{margin-left:4px;vertical-align:middle} .dk-chat svg{width:14px;height:14px;vertical-align:-2px;color:var(--blue)}
.dk-pages{margin-left:auto;display:flex;gap:8px;align-items:center;font-size:12px} .dk-pages select{width:auto;font-size:12px;padding:3px 6px}
@media(max-width:700px){.dk-filt{padding:0 12px 8px} .dk-filt input[type=search]{max-width:none;flex:1 0 100%} .dk-pages{margin-left:0;flex:1 0 100%} .dk-note .pop{width:calc(100vw - 16px)}}
/* build 193.2 (Jon 9/16): resizable columns, OPT-IN. The default is the auto-width table that .tw scrolls sideways, untouched. A drag on a
   header's right edge (script in desk_home.html) freezes every column at its drawn width, marks the table .sized, and from then on moves
   one column at a time in pixels; the table keeps scrolling. Reset columns forgets it. Under 700px the handles are gone and phone.js folds
   the real table into cards as before. */
.dk-home table#dealgrid.sized{table-layout:fixed} .dk-home #dealgrid.sized th{overflow:hidden} .dk-home #dealgrid.sized th a{white-space:normal}
.dk-home #dealgrid.sized td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .dk-home #dealgrid.sized td.wrap{white-space:normal;overflow-wrap:anywhere}
.dk-home th{position:relative} .dk-home th .rz{position:absolute;top:0;right:-4px;width:8px;height:100%;cursor:col-resize;touch-action:none;z-index:2}
.dk-home th .rz:hover,.dk-home th .rz.on{background:rgba(31,95,191,.28)}
#colreset{font-size:11.5px;margin-left:8px}
@media(max-width:700px){.dk-home th .rz,#colreset{display:none}}

/* build 288 -- refresh in the top bar */
.top .user .hq-refresh{border:0;background:transparent;color:inherit;font-size:19px;line-height:1;width:34px;height:34px;border-radius:8px;cursor:pointer;opacity:.85;display:inline-grid;place-items:center}
.top .user .hq-refresh:hover{background:rgba(255,255,255,.12);opacity:1}
.top .user .hq-refresh.spin{animation:hqspin .8s linear infinite}
@keyframes hqspin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.top .user .hq-refresh.spin{animation:none}}
/* build 306 (Tyler 9/19, the nit on HQ #175): on a phone the top bar's right half — refresh + three bells + the avatar — took ~220px of a
   375px screen and could push the avatar past the edge on a Desk page with a long title. The bar is chrome: it never overflows, the
   right half never shrinks or grows, and the title takes what is left and ellipses. Bells + refresh tighten up under 480px. */
@media(max-width:700px){
 .top{overflow:hidden;max-width:100vw;box-sizing:border-box}
 .top h1{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
 .top .user{flex:0 0 auto;margin-left:auto}
}
@media(max-width:480px){
 .top .user{gap:2px} .bell{margin-right:0} .bell>button{padding:4px}
 .top .user .hq-refresh{width:28px;height:28px;font-size:17px}
 .avatar{width:26px;height:26px;font-size:11px}
}
