
  :root{
    --bg:#0a0a0b; --panel:#101012; --panel2:#17171a; --line:rgba(255,255,255,.08);
    --bg-2:#0b0b0d; --card-hi:#141416; --card-lo:#0e0e10;
    --surface:#1a1a1e; --surface-hi:#212127; --well:#08080a;
    --ink:#ffffff; --dim:rgba(255,255,255,.78); --gold:#ffcc33; --gold-2:#f0a500; --gold-ink:#0a0a0a;
    --probate:#8b5cf6; --preforeclosure:#ff5c5c; --fsbo:#4c9dd9; --expired:#ffb020; --likely-to-sell:#4cd9c8;
    --call:#ff5c8a; --sms:#4c9dd9; --email:#b98cff; --mail:#4cd9c0; --camp:#ffcc33;
    --display:'Archivo',sans-serif; --body:'Sora',sans-serif;
    /* 🔴 4px, DOWN FROM 5. Every rounded corner reads from this one
       token, so squaring the interface is a single value — and a
       tighter radius is what separates a tool from a toy. */
    --radius:4px;
    /* ⚠ Elevation as tokens, not one-off shadows. A card that lifts
       the same amount everywhere is what makes an interface feel
       built rather than assembled. */
    --lift-1:0 1px 2px rgba(0,0,0,.4);
    --lift-2:0 1px 2px rgba(0,0,0,.4), 0 6px 16px -8px rgba(0,0,0,.65);
    --lift-3:0 2px 4px rgba(0,0,0,.45), 0 16px 34px -12px rgba(0,0,0,.75);
  }
  *{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
  html,body{background:var(--bg);min-height:100vh;width:100%}
  body{font-family:var(--body);color:var(--ink);width:100%;max-width:100%;margin:0;padding:0}
































  /* 🔴 THE 86px RESERVATION IS GONE, AND ON PURPOSE. It was a
     hard-coded guess at the bar's height, with a comment admitting the
     two had to be edited together -- which is a defect waiting on the
     next font change. It was also applied at EVERY width, so a desktop
     dashboard carried 86px of empty space under it for a bar that
     should never have been there.

     nav.js now measures its own bar after paint and sets
     body.paddingBottom from that, only on the widths where a bar
     exists. Do not put a number back here. */
  .app{width:100%;max-width:100%;min-height:100vh;background:var(--bg);position:relative;display:flex;flex-direction:column}
  .screen{width:100%;max-width:100%;position:relative;padding-bottom:40px}
































  .topbar{width:100%;max-width:100%;padding:16px 32px;position:sticky;top:0;background:linear-gradient(var(--bg),var(--bg) 80%,transparent);z-index:50;
    display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line)}
  .topbar .wm{font-family:var(--display);font-weight:900;font-size:24px;letter-spacing:-.2px}
  /* FIXED .right IS THE ONLY CHILD OF .topbar NOW, because the wordmark
     was removed in an earlier build. justify-content:space-between with a
     single item puts it at the START, so the whole cluster collapsed to
     the left and the Engine indicator sat wherever the alert text ended.
     Its position moved with the length of that text, and moved again when
     the alert was emptied. Filling the row and anchoring the Engine right
     gives it one fixed home instead. */
  .topbar .right{display:flex;align-items:center;gap:22px;flex:1;min-width:0}
  .alert{display:flex;gap:8px;align-items:center;font-size:14px;color:var(--dim);
    background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:9px 16px}
  .alert b{color:var(--gold-text,var(--gold));font-family:var(--display);font-weight:900}
  .alert .dot{width:5px;height:5px;border-radius:50%;background:var(--dim)}
































  /* CRITICAL: margin-left:auto, OR THE ENGINE MOVES EVERY TIME THE ALERT
     DOES. The alert is now hidden on a good load and shown on an error,
     so without this the indicator would jump sideways the moment a
     session expired -- at exactly the moment an agent is looking for it
     to tell them whether the system is up. Anchored to the right edge it
     is in the same place in every state. */
  .cosline{display:flex;align-items:center;gap:10px;margin-left:auto}
  .cosline .coslabel{font-family:var(--display);font-weight:700;font-size:14px;color:var(--dim);letter-spacing:.3px}
  .cos{position:relative;width:22px;height:22px;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center}
  .cos::before{content:"";position:absolute;inset:0;border-radius:50%;border:1.5px solid var(--gold);opacity:.85}
  .cos::after{content:"";position:absolute;inset:-6px;border-radius:50%;border:1.5px solid var(--gold);opacity:0;animation:cosRing 2.6s ease-out infinite}
  .cos-core{width:9px;height:9px;border-radius:50%;
    background:radial-gradient(circle at 35% 30%,#ffe07a,var(--gold) 65%,#e8a900);
    box-shadow:0 0 8px rgba(255,204,51,.85),0 0 18px rgba(255,204,51,.45);
    animation:cosPulse 2.6s ease-in-out infinite}
  @keyframes cosPulse{0%,100%{transform:scale(1);box-shadow:0 0 7px rgba(255,204,51,.7),0 0 15px rgba(255,204,51,.35)}
    50%{transform:scale(1.22);box-shadow:0 0 12px rgba(255,204,51,1),0 0 26px rgba(255,204,51,.6)}}
  @keyframes cosRing{0%{transform:scale(.75);opacity:.55}70%{opacity:0}100%{transform:scale(1.35);opacity:0}}
































  .maincontent{width:100%;max-width:100%;padding:0 32px;display:grid;grid-template-columns:2fr 1fr;gap:28px;align-items:start}
  @media (max-width:1100px){ .maincontent{grid-template-columns:1fr} }
































  /* FIXED flex-wrap ADDED. Without it the row could not wrap, so once
     the view select and + Add lead together exceeded the width the
     button was pushed outside the page rather than onto a second line.
     NOTE It also fixes a latent bug: the @media(max-width:600px) rule
       below sets .sectionhead .dncwrap{width:100%}, which could never
       take effect while the row was nowrap. */
  .sectionhead{display:flex;align-items:center;flex-wrap:wrap;gap:9px;padding:22px 0 14px;font-family:var(--display);font-weight:900;font-size:20px}
































  .sectionhead .dncwrap{margin-left:auto;display:flex;align-items:center;gap:8px}
  .dncbtn{background:none;border:1px solid var(--line);border-radius:5px;
    color:var(--dim);font-family:var(--display);font-weight:700;font-size:12px;
    letter-spacing:.02em;padding:7px 13px;cursor:pointer;display:flex;align-items:center;
    gap:7px;white-space:nowrap;transition:border-color .15s,color .15s}
  .dncbtn:hover{border-color:var(--gold);color:var(--muted)}
  .dncbtn .dot{width:7px;height:7px;border-radius:50%;background:var(--dim);flex:none}
  .dncbtn.clear{border-color:rgba(76,217,123,.4);color:var(--green)}
  .dncbtn.clear .dot{background:var(--green)}
  .dncbtn.flagged{border-color:rgba(255,92,92,.4);color:#ff8a8a}
  .dncbtn.flagged .dot{background:#ff5c5c}
  @media(max-width:600px){
    .sectionhead .dncwrap{margin-left:0;width:100%;margin-top:8px}
    .dncbtn{font-size:13px;padding:6px 10px}
    /* 6 Oct 2026 (QA 6c): on a phone the address wraps instead of losing
       its ZIP to an ellipsis ("Saint James City, FL, 339..."). */
    .lead .ad{white-space:normal;overflow:visible;text-overflow:clip}
    .screen{overflow-x:hidden}
  }
































  .drawer{margin:18px 0 6px;grid-column:1 / -1}
  .drawer-toggle{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
    padding:15px 20px;display:flex;align-items:center;justify-content:space-between;cursor:pointer;
    font-family:var(--display);font-weight:800;font-size:15px;color:var(--ink);transition:border-color .15s}
  .drawer-toggle .lft{display:flex;align-items:center;gap:10px}
  .drawer-toggle .lft svg{width:18px;height:18px;stroke:var(--gold);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
  .drawer-toggle .mini{display:flex;gap:18px;font-family:var(--body);font-weight:400;font-size:14.5px;color:var(--dim)}
  .drawer-toggle .mini b{color:var(--gold-text,var(--gold));font-family:var(--display);font-weight:900}
  .drawer-toggle .chev{color:var(--dim);font-size:16px;transition:transform .3s;margin-left:4px}
  .drawer.open .drawer-toggle{border-color:rgba(255,204,51,.3);border-radius:var(--radius) var(--radius) 0 0}
  .drawer.open .chev{transform:rotate(180deg)}
  .drawer-body{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(.16,1,.3,1);
    background:var(--panel);border:1px solid var(--line);border-top:none;border-radius:0 0 var(--radius) var(--radius)}
  .drawer.open .drawer-body{max-height:900px}
  .drawer-inner{padding:18px 20px 22px;display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
  @media (max-width:1100px){ .drawer-inner{grid-template-columns:1fr 1fr} }
  @media (max-width:700px){ .drawer-inner{grid-template-columns:1fr} }
































  .wcard{background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);padding:18px}
  .wcard h4{font-family:var(--display);font-weight:800;font-size:14px;margin-bottom:14px}
  .creditrow{display:flex;align-items:center;gap:18px}
  .cgauge{position:relative;width:96px;height:96px;flex:none}
  .cgauge svg{transform:rotate(-90deg)}
  .cgauge .ct{fill:none;stroke:#241d05;stroke-width:9}
  .cgauge .cf{fill:none;stroke:url(#cg);stroke-width:9;stroke-linecap:round;filter:drop-shadow(0 0 4px rgba(255,204,51,.5))}
  .cgauge .cc{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
  .cgauge .cc .n{font-family:var(--display);font-weight:900;font-size:20px;color:var(--gold-text,var(--gold));line-height:1}
  .cgauge .cc .l{font-size:13px;color:var(--dim);margin-top:1px}
  .creditrow .meta{font-size:14.5px;color:var(--dim);line-height:1.6}
  .creditrow .meta b{color:var(--ink);font-family:var(--display);font-weight:700}
  .sbar{margin-bottom:10px}
  .sbar:last-child{margin-bottom:0}
  .sbar .lab{display:flex;justify-content:space-between;font-size:14.5px;margin-bottom:4px}
  .sbar .lab b{font-family:var(--display);font-weight:800}
  .sbar .rail{height:15px;background:var(--card-hi);border-radius:var(--radius);overflow:hidden}
  .sbar .fill{height:100%;background:linear-gradient(90deg,var(--gold-2),var(--gold));border-radius:var(--radius)}
  .runrow{display:flex;gap:12px;align-items:baseline;padding:9px 0;border-bottom:1px solid var(--line);font-size:14.5px}
  .runrow:last-child{border:none}
  .runrow .tm{font-family:var(--display);font-weight:800;color:var(--gold-text,var(--gold));min-width:66px;font-size:14px}
  .runrow .ds{color:var(--dim)}
  .stattiles{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  .stile{background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);padding:13px 14px}
  .stile.wide{grid-column:1 / -1}
  .stile .lbl{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--dim);
    font-family:var(--display);font-weight:700;letter-spacing:.3px;margin-bottom:5px}
  .stile .lbl svg{width:13px;height:13px;stroke:var(--gold);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
  .stile .val{font-family:var(--display);font-weight:900;font-size:24px;color:var(--gold-text,var(--gold));line-height:1}
  .stile .val small{font-family:var(--body);font-weight:400;font-size:13px;color:var(--dim);margin-left:4px}
































  .leadcol{grid-column:1;display:flex;flex-direction:column;min-width:0}
  .deck{display:flex;flex-direction:column;gap:16px}
  .sidebar{grid-column:2;display:flex;flex-direction:column;gap:20px}
  /* 28 Sep 2026, Jason: "Activities Feed", "Leads Delivered" and "Lead Map"
     are real-estate panels (delivered finder leads, a map of scored leads)
     and do not belong on a trade's Dashboard. Real estate keeps all three.
     The list takes the full width in their place. */
  html[data-aud="trade"] .sidebar,
  html[data-aud="trade"] .mapsection,
  /* 28 Sep 2026, Jason: the Overview drawer (leads by signal, monthly
     gauge, ZIPs) is real estate's too -- "52 of 86 leads, 3 ZIPs" is the
     finder's delivery count, not a contractor's number. */
  html[data-aud="trade"] #drawer{display:none !important}
  html[data-aud="trade"] .leadcol{grid-column:1 / -1}
  /* 1 Oct 2026, Jason: "the real estate page now reads like a roofer
     dashboard". The "Prospects near the map" strip (doors / leads /
     prospects around the last map spot) is the canvassing view. Real
     estate's Dashboard is the lead deck; the strip is trades only. */
  html:not([data-aud="trade"]) #mapArea{display:none !important}
  .lead{background:linear-gradient(180deg,var(--card-hi),var(--card-lo));border:1px solid var(--line);
    border-radius:var(--radius);padding:20px 20px 18px;position:relative;overflow:visible;transition:transform .15s}
  .lead.hot{border-color:rgba(255,204,51,.35)}
  .lead.hot::before{content:"";position:absolute;inset:0;border-radius:var(--radius);pointer-events:none;box-shadow:inset 0 0 30px rgba(255,204,51,.09)}
  .lead .toprow{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}
  .lead .who{flex:1;min-width:0;cursor:pointer}
  .lead .nm{font-family:var(--display);font-weight:900;font-size:21px;letter-spacing:-.3px;display:inline-flex;align-items:center;gap:8px}
  .lead .nm .chev{color:var(--dim);font-size:14px;font-weight:400;transition:transform .3s}
  .lead .who.expanded .nm .chev{transform:rotate(90deg);color:var(--gold-text,var(--gold))}
  .lead .ad{font-size:14px;color:var(--dim);margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pill{display:inline-block;font-family:var(--display);font-weight:800;font-size:12px;letter-spacing:.6px;
    text-transform:uppercase;color:#fff;border-radius:var(--radius);padding:4px 12px;margin-top:10px}
  .est{font-size:14px;color:var(--dim);margin-top:10px}
  .est b{color:var(--ink);font-weight:700}
/* 28 Sep 2026: the trade card (render(), TRADE_DECK) */
.tcard .ttag{color:#9d74e8;font-weight:600;font-size:14px;margin-top:6px;line-height:1.4}
:root[data-theme="light"] .tcard .ttag{color:#7c4dcc}
.tcard .tdist{color:var(--dim);font-size:14px;white-space:nowrap;flex:none}
.tcard .tct{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;margin-top:10px;font-size:14px}
.tcard .tct .k{color:var(--dim);font-weight:600}
/* 29 Sep 2026 (QA #17): nothing on a card may be wider than the card --
   long owner names, prospect lines, contact lists and the fold-out summary
   wrap; the distance keeps its own column. */
.deck,.lead,.lead .toprow{min-width:0;max-width:100%}
.lead .nm{max-width:100%;overflow-wrap:anywhere}
.tcard .ad,.tcard .ttag,.tcard .tct .v{overflow-wrap:anywhere;min-width:0}
.tcard .tacts summary{white-space:normal;overflow-wrap:anywhere}
details.tacts{margin-top:12px;border-top:1px solid var(--line);padding-top:4px}
details.tacts>summary{cursor:pointer;color:var(--gold-text,var(--gold));font-weight:600;font-size:14px;list-style:none;padding:10px 0;min-height:24px}
details.tacts>summary::-webkit-details-marker{display:none}
details.tacts>summary::after{content:" \25BE"}
details.tacts[open]>summary::after{content:" \25B4"}
details.tacts .actions{margin-top:4px}
/* 30 Sep 2026, Jason (mock-up approved): the trade row EXPANDS on tap to show
   the workflow -- Call, Text, Email, Postcard and the steps for this
   contact. Hidden until the contact is tapped; one open at a time. */
.tcard .trow{cursor:pointer}
.tcard .tout{display:inline-block;margin-top:6px;font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  padding:3px 8px;border-radius:6px;background:rgba(255,204,51,.14);color:var(--gold-text,var(--gold))}
:root[data-theme="light"] .tcard .tout{color:#7a5a00;background:#f6ecd0}
.tcard .tchev{flex:none;width:30px;height:30px;border-radius:50%;border:1px solid var(--line);display:grid;place-items:center;
  color:var(--dim);font-size:13px;background:transparent;cursor:pointer;transition:transform .2s}
.tcard.txopen{border-color:rgba(255,204,51,.55);box-shadow:0 0 0 2px rgba(255,204,51,.18)}
.tcard.txopen .tchev{transform:rotate(180deg);background:var(--gold);border-color:var(--gold);color:#111}
.tcard .tx{display:none;margin-top:12px;border-top:1px dashed var(--line);padding-top:12px}
.tcard.txopen .tx{display:block}
.tcard .tx .actions{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}
.tcard .tx .act.tnext{outline:2px solid var(--gold);outline-offset:1px}
.tcard .tx .ttext{cursor:pointer}
.tcard .tflow{margin-top:12px;border-radius:10px;padding:10px 12px;background:rgba(255,204,51,.06);border:1px solid rgba(255,204,51,.18)}
.tcard .tflow .tfh{font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);margin-bottom:6px}
.tcard .tflow .tst{display:flex;gap:9px;align-items:flex-start;font-size:14px;line-height:1.4;padding:3px 0}
.tcard .tflow .tst i{flex:none;width:19px;height:19px;border-radius:50%;border:1.5px solid var(--gold);font-style:normal;font-size:10.5px;
  font-weight:700;display:grid;place-items:center;color:var(--gold-text,var(--gold));margin-top:1px}
.tcard .tflow .tst.done i{background:var(--gold);color:#111}
.tcard .tflow .tst.now{font-weight:700}
.tcard .tflow .tst.warn{color:var(--red,#d9534f)}
.tcard .tmore{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.tcard .tmore button{flex:1 1 auto;min-width:0;font:inherit;font-size:13.5px;padding:8px 10px;border-radius:9px;border:1px solid var(--line);
  background:transparent;color:var(--ink);cursor:pointer}
.tcard .tback{display:none;margin:0 0 10px;font-size:13.5px;color:var(--gold-text,var(--gold));font-weight:600;cursor:pointer;background:none;border:0;padding:0}
.tcard.fromq .tback{display:inline-block}
@media (max-width:420px){ .tcard .tx .actions{gap:6px} }
































  .score{position:relative;flex:none;width:46px;height:46px;display:flex;align-items:center;justify-content:center}
  .score .circle{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;
    font-family:var(--display);font-weight:900;font-size:18px;position:relative;z-index:2}
  .score.hot .circle{background:radial-gradient(circle at 35% 30%,#ffe07a,var(--gold) 60%,#e8a900);
    color:var(--gold-ink);box-shadow:0 0 13px rgba(255,204,51,.6),0 0 24px rgba(255,204,51,.3)}
  .score.hot{animation:glow 2.4s ease-in-out infinite}
  @keyframes glow{0%,100%{filter:drop-shadow(0 0 3px rgba(255,204,51,.4))}50%{filter:drop-shadow(0 0 10px rgba(255,204,51,.75))}}
  .score.warm .circle{background:none;border:2px solid var(--gold);color:var(--gold-text,var(--gold))}
  .score.cool .circle{background:none;border:2px solid rgba(255,255,255,.25);color:var(--dim)}
  /* 29 Sep 2026: letter grades A-D (badge()). A is the old 80+ glow. */
  .score.grade-a .circle{background:radial-gradient(circle at 35% 30%,#ffe07a,var(--gold) 60%,#e8a900);
    color:var(--gold-ink);box-shadow:0 0 13px rgba(255,204,51,.6),0 0 24px rgba(255,204,51,.3)}
  .score.grade-a{animation:glow 2.4s ease-in-out infinite}
  .score.grade-b .circle{background:rgba(255,204,51,.10);border:2px solid var(--gold);color:var(--gold-text,var(--gold));box-shadow:0 0 10px rgba(255,204,51,.35)}
  .score.grade-b{animation:glowsoft 3s ease-in-out infinite}
  @keyframes glowsoft{0%,100%{filter:drop-shadow(0 0 1px rgba(255,204,51,.25))}50%{filter:drop-shadow(0 0 6px rgba(255,204,51,.5))}}
  .score.grade-c .circle{background:none;border:2px solid var(--gold-dim, #c9a02c);color:var(--gold-dim, #c9a02c)}
  .score.grade-d .circle{background:none;border:2px solid rgba(255,255,255,.25);color:var(--dim)}
  [data-theme="light"] .score.grade-a .circle{color:#18181b}
  [data-theme="light"] .score.grade-d .circle{border-color:rgba(0,0,0,.25)}
  @media (prefers-reduced-motion:reduce){.score.grade-a,.score.grade-b{animation:none}}
































  .actions{display:flex;flex-direction:row;flex-wrap:nowrap;gap:6px;margin-top:14px}
  /* ⚠ THIS RULE WINS. There is an earlier .act at the top of the file
     with padding:8px 6px 14px and an @media(max-width:380px) override
     -- both come BEFORE this one and neither has higher specificity, so
     this is the padding that actually applies. Editing the top one
     changes nothing, which is worth knowing before spending twenty
     minutes on it. Same for .act svg: the 23px and 20px rules up there
     are dead, and the live size is the one below. */
  .act{position:relative;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);flex:1 1 0;
    padding:6px 8px 18px;
    /* 🔴 space-evenly, AND THE BOTTOM PADDING IS WHAT MAKES IT WORK.
       .more is position:absolute at bottom:4px, so it is out of flow and
       contributes nothing to the layout. Reserving its height in the
       padding means the flow box ends where the dots begin, and
       space-evenly then puts the label midway between the icon and them
       instead of tucked 2px under the icon with a hole underneath. */
    /* ⚠ gap:12px IS NOT "12px between icon and label" -- it is the
       amount that DOUBLES it. space-evenly splits the free space into
       three equal parts, so the middle gap is (flow height - content)/3.
       Adding g leaves (free-g)/3 either side and (free-g)/3 + g in the
       middle, and that equals twice the original when g = free/2.
       Phone: ~80px button, 6/18 padding -> 56 flow, ~32 content,
       24 free, so 12. Desktop: 74px, 48 flow, 16 free, and the same 12
       still lands close without overflowing. One value, both sizes.
       ⚠ If the icon or the label size changes, this number is wrong
         again -- it is derived from them, not independent of them. */
    display:flex;flex-direction:column;align-items:center;justify-content:space-evenly;gap:12px;cursor:pointer;min-width:0;
    transition:transform .1s,border-color .15s,background .15s}
  .act:active{transform:scale(.95)}
  /* 🔴 THE SQUARE HAS TO STOP SOMEWHERE. aspect-ratio:1 ties height to
     width, which is right on a phone -- four buttons across ~340px give
     four ~80px squares. On a 1200px card the same rule gives four 265px
     buttons: a quarter of the screen each, for "Email".
     ⚠ The fix is to stop being square above a width where square stops
       making sense, not to cap the height -- capping height while
       aspect-ratio is still in force fights the same declaration from
       two directions and the loser depends on source order.
     ⚠ Phone-first: this is min-width, so everything below 560px keeps
       the squares untouched. */
  @media (min-width:560px){
    .act{aspect-ratio:auto;height:74px;padding:8px 6px 18px}
  }
  /* ⚠ 19px, up from 15. The two larger rules earlier in the file (23px,
     and 20px under 380px) never applied -- this one is last and wins
     everywhere -- so the icons had been rendering at the smallest of
     the three sizes on every screen. */
  .act svg{width:19px;height:19px;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
  .act .t{font-family:var(--display);font-weight:700;font-size:12px;letter-spacing:.2px;text-transform:uppercase;color:var(--dim);white-space:nowrap}
  .act[data-c=call] svg{stroke:var(--call)} .act[data-c=call]:active{border-color:var(--call)}
  .act[data-c=sms] svg{stroke:var(--sms)} .act[data-c=sms]:active{border-color:var(--sms)}
  .act[data-c=email] svg{stroke:var(--email)} .act[data-c=email]:active{border-color:var(--email)}
  .act[data-c=mail] svg{stroke:var(--mail)} .act[data-c=mail]:active{border-color:var(--mail)}
  .act[data-c=camp] svg{stroke:var(--camp)} .act[data-c=camp]:active{border-color:var(--camp)}
  /* hard block — no screened number exists */
  /* Same reasoning: the lock is now a door, so it must look like one. */
/* 🔴 RENDERED AT .62 OPACITY WITH A GREYED ICON, WHICH READS AS BROKEN
      RATHER THAN AS A STEP TO TAKE. Both states are pressable and
      always were -- 'nonum' opens number capture, 'locked' opens the
      screening gate. Full opacity now; the dot says there is something
      to know and the gate says what.
   ⚠ The CLASSES still drive click routing. Do not remove them. */
.act.locked{opacity:1;cursor:pointer}
/* Matches .addlead's height so the row stays level. */
/* ⚠ WHITE, NOT --muted. At rgba(245,245,243,.80) a thin outline icon on
     a near-black card is close to invisible -- it rendered correctly and
     could not be found. Contrast is not decoration here; an action the
     agent cannot see does not exist. */
/* Second row of the drawer: four campaign cards, wrapping to two on
   narrow screens. */
.alnext{width:100%;background:#0d0d0f;border:1px solid rgba(255,255,255,.16);
  border-radius:9px;padding:11px 13px;color:#fff;cursor:pointer;font-family:var(--body)}
.alnext:hover{border-color:rgba(255,204,51,.5)}
.alnext b{display:block;font-size:14px}
.alnext span{display:block;font-size:13px;color:rgba(255,255,255,.68);margin-top:2px}
.alnext.ghost{background:none}
.alnext:disabled{opacity:.55;cursor:default}
.fieldchips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 8px}
.fieldchips .chip{font-family:var(--mono,monospace);font-size:13px;padding:4px 8px;
  border-radius:6px;cursor:pointer;background:rgba(255,204,51,.08);
  border:1px solid rgba(255,204,51,.28);color:#ffcc33}
.fieldchips .chip:hover{background:rgba(255,204,51,.18)}
/* Reads like paper, not like a form field -- the point is to judge the
   sentence, so it should not look editable. */
.tprev{background:#0d0d0f;border:1px solid rgba(255,255,255,.12);border-radius:8px;
  padding:12px 13px;font-family:var(--body);font-size:14.5px;line-height:1.65;
  color:rgba(245,245,243,.9);min-height:60px;white-space:normal}
/* ⚠ A field the sender cannot fill is marked, not rendered. The task
     would fail at send time on a leftover token. */
.badfield{background:rgba(255,92,92,.15);color:#ff5c5c;border-radius:4px;
  padding:1px 4px;font-family:var(--mono,monospace);font-size:14.5px}
.camprow{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;
  grid-column:1/-1;margin-top:14px}
@media(max-width:900px){.camprow{grid-template-columns:repeat(2,1fr)}}
/* ⚠ Narrowed so the view select, the search icon and + Add lead fit on
     ONE row on a phone. Comments elsewhere in this file record that row
     overflowing twice before. */
@media(max-width:620px){
  .sectionhead select{max-width:132px}
  .searchlead{margin-right:6px}
}
/* 29 Sep 2026 (QA #61): at 390 the filter clipped to "Ideal pros..." (116px
   of text in a 94px box) and the AI label could wrap away from its dot.
   On a phone the filter takes its own full-width line; search, + Add and
   AI share the next one, and AI never splits from its dot. */
@media(max-width:480px){
  .sectionhead select.viewsel{flex:1 1 100%;width:100%;max-width:none;min-width:0}
  .sectionhead .cosline{flex:none;white-space:nowrap}
}
/* 🔴 IT WAS A BLANK WHITE BOX IN LIGHT MODE. color was hardcoded
   #ffffff and the icon draws with stroke:currentColor -- so on a white
   card the magnifier was white on white. Seen 8 Sep in the live light
   theme; the button was there and looked like an empty tile.
   ⚠ --ink IS THE BODY TEXT COLOUR and already flips per theme, so it
     is the right token: light on dark, #000 on light. The literals stay
     as fallbacks for a page that loads without hub.css. */
.searchlead{display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;margin-right:8px;border-radius:9px;cursor:pointer;
  background:var(--card,#17171a);border:1px solid var(--line2,rgba(255,255,255,.28));
  color:var(--ink,#ffffff)}
.searchlead:hover{border-color:var(--gold,#ffcc33);color:var(--gold,#ffcc33)}
.searchlead.on{border-color:var(--gold,#ffcc33);color:var(--gold,#ffcc33);
  background:rgba(255,204,51,.08)}
.mx-act-item{position:relative}
.mx-act-item:hover{border-color:rgba(255,204,51,.45)}
.mx-go{position:absolute;right:12px;top:50%;transform:translateY(-50%);
  font-size:14px;color:#ffcc33;opacity:.75}
/* Small and lit rather than large. The glow is what makes a 7px dot
   readable against a dark card without it becoming a badge.
   ⚠ Red pulses, green does not. A litigator is the one state worth
     pulling the eye; animating both would make neither mean anything. */
.pdot{position:absolute;top:6px;right:6px;width:7px;height:7px;border-radius:50%;
  box-shadow:0 0 0 1.5px var(--card,#17171a)}
.pdot.green{background:#4cd97b;
  box-shadow:0 0 0 1.5px var(--card,#17171a),0 0 6px 1px rgba(76,217,123,.85),
             0 0 12px 2px rgba(76,217,123,.35)}
/* Amber: a number exists but nobody has checked it inside 31 days.
   ⚠ THIS IS THE STATE THE DOT DID NOT HAVE, AND IT IS THE COMMON ONE.
     120 of 337 displayed numbers are unscreened right now. Rendering
     them green said "checked and clear" about numbers nobody had
     looked at. Amber does not pulse -- red is the only state worth
     pulling the eye. */
.pdot.amber{background:#ffb020;
  box-shadow:0 0 0 1.5px var(--card,#17171a),0 0 6px 1px rgba(255,176,32,.8),
             0 0 12px 2px rgba(255,176,32,.3)}
.pdot.red{background:#ff5c5c;
  box-shadow:0 0 0 1.5px var(--card,#17171a),0 0 6px 1px rgba(255,92,92,.9),
             0 0 14px 3px rgba(255,92,92,.4);
  animation:pdotPulse 2.4s ease-in-out infinite}
@keyframes pdotPulse{
  0%,100%{box-shadow:0 0 0 1.5px var(--card,#17171a),0 0 6px 1px rgba(255,92,92,.9),
                     0 0 14px 3px rgba(255,92,92,.4)}
  50%    {box-shadow:0 0 0 1.5px var(--card,#17171a),0 0 8px 2px rgba(255,92,92,1),
                     0 0 20px 5px rgba(255,92,92,.55)}}
/* ⚠ Respect the OS setting. A pulsing dot on every card is exactly
     what reduced-motion exists for. */
@media(prefers-reduced-motion:reduce){.pdot.red{animation:none}}
.act.locked:hover{opacity:.85;border-color:rgba(255,204,51,.35)}
  /* Icons stay at full strength -- see the note on .act.locked. */
  /* soft gate — the channel works, consent doesn't exist yet */
  .act.gated{opacity:1;border-style:dashed;border-color:rgba(255,255,255,.22)}
  .act.gated svg{stroke:#ffffff !important;opacity:1}
  .act.gated .t{color:rgba(255,255,255,.82)}
  .act .lockmini{position:absolute;top:5px;right:6px;font-size:13px}
  .act .gatemini{position:absolute;top:4px;right:5px;font-size:13px;color:var(--dim);font-family:var(--display);font-weight:800}
  /* FIXED A LONG PRESS ON iOS WAS FIGHTING THE BROWSER. Without these
     three, holding a button raises the text-selection handles and the
     callout menu, which steals the gesture and looks broken. They are
     the standard set for anything that responds to a hold.
     NOTE touch-action:manipulation also removes the legacy 300ms tap
       delay, so the short press -- the call -- fires sooner. */
  .act{touch-action:manipulation;user-select:none;-webkit-user-select:none;
    -webkit-touch-callout:none}
  .act .more{position:absolute;bottom:4px;left:50%;transform:translateX(-50%);display:flex;gap:2px}
  /* FIXED THE DOTS WERE A 12px TAP TARGET. They are the only
     discoverable way into the menu -- a long press is not discoverable
     and never will be -- so the hit area is widened to something a thumb
     can land on. The dots stay the same size; only the invisible target
     grows, so nothing moves on screen. */
  .act .more::after{content:'';position:absolute;left:50%;top:50%;
    transform:translate(-50%,-50%);width:44px;height:26px}
  .act .more i{width:2.5px;height:2.5px;border-radius:50%;background:var(--dim);display:block}
  .act .press{position:absolute;inset:-1px;border-radius:var(--radius);pointer-events:none}
  .act.pressing .press{box-shadow:0 0 0 2px var(--gold);animation:fillact .5s linear forwards}
  @keyframes fillact{from{clip-path:inset(100% 0 0 0)}to{clip-path:inset(0 0 0 0)}}
  .act.menuopen{border-color:rgba(255,204,51,.6);background:#232328}
  .act.menuopen .more i{background:var(--gold)}
































  .inlinewrap{max-height:0;overflow:hidden;opacity:0;margin-top:0;position:relative;z-index:40;
    transition:max-height .34s cubic-bezier(.16,1,.3,1),opacity .22s,margin-top .3s}
  .inlinewrap.open{max-height:620px;opacity:1;margin-top:14px}
  .inlinebox{background:var(--panel2);border:1px solid rgba(255,204,51,.28);border-radius:var(--radius);padding:6px;position:relative}
  .inlinebox::before{content:"";position:absolute;top:-6px;width:11px;height:11px;background:var(--panel2);
    border-left:1px solid rgba(255,204,51,.28);border-top:1px solid rgba(255,204,51,.28);
    transform:rotate(45deg);left:var(--arrow,30px);transition:left .28s cubic-bezier(.16,1,.3,1)}
  .inlinebox .ihd{font-family:var(--display);font-weight:800;font-size:12px;letter-spacing:.9px;
    text-transform:uppercase;color:var(--gold-text,var(--gold));padding:11px 13px 9px;display:flex;align-items:center;gap:8px}
  .iopt{display:flex;align-items:center;gap:13px;padding:13px;border-radius:var(--radius);cursor:pointer;transition:background .15s}
  .iopt:active{background:#222226}
  .iopt .iic{width:36px;height:36px;border-radius:var(--radius);background:#1e1e22;display:flex;align-items:center;justify-content:center;flex:none}
  .iopt .iic svg{width:18px;height:18px;stroke:var(--gold);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
  .iopt .itx .a{font-family:var(--display);font-weight:700;font-size:14.5px}
  .iopt .itx .b{font-size:14px;color:var(--dim);margin-top:1px}
  .iopt.lockrow{opacity:.45}
  .ilane{margin:6px 6px 2px;background:rgba(255,92,92,.1);border:1px solid rgba(255,92,92,.3);
    border-radius:var(--radius);padding:11px 13px;font-size:14px;color:#ffb3b3;line-height:1.45}
  .ilane b{color:#ff8a8a}
































  .propwrap{max-height:0;overflow:hidden;opacity:0;margin-top:0;
    transition:max-height .42s cubic-bezier(.16,1,.3,1),opacity .25s,margin-top .3s}
  .propwrap.open{max-height:900px;opacity:1;margin-top:15px}
  .propbox{background:var(--panel2);border:1px solid rgba(255,204,51,.28);border-radius:var(--radius);overflow:hidden;
    display:grid;grid-template-columns:1fr 1fr}
  @media (max-width:800px){ .propbox{grid-template-columns:1fr} }
  .propsv{min-height:220px;position:relative;background:linear-gradient(135deg,#3a4a5a,#1a2530);
    display:flex;align-items:center;justify-content:center}
  .propsv .gmap{width:100%;height:100%;object-fit:cover;position:absolute;inset:0}
  .propsv .svph{color:rgba(255,255,255,.68);font-family:var(--display);font-weight:800;font-size:14px;
    text-align:center;line-height:1.6;padding:0 20px;letter-spacing:.5px;position:relative;z-index:1}
  .propsv .svtag{position:absolute;bottom:10px;left:13px;background:rgba(0,0,0,.72);border-radius:var(--radius);
    padding:6px 11px;font-size:13px;font-family:var(--display);font-weight:700;display:flex;align-items:center;gap:6px;z-index:2}
  .propsv .svtag svg{width:12px;height:12px;stroke:var(--gold);fill:none;stroke-width:2}
  .propbd{padding:16px 18px 18px}
  .prow{display:flex;justify-content:space-between;padding:10px 0;border-bottom:1px solid var(--line);font-size:14.5px}
  .prow:last-of-type{border:none}
  .prow .l{color:var(--dim)}
  .prow .v{font-family:var(--display);font-weight:700}
  .pwhy{background:var(--card-lo);border:1px solid var(--line);border-radius:var(--radius);padding:14px;margin-top:13px}
  .pwhy .h{font-family:var(--display);font-weight:800;font-size:12px;letter-spacing:.9px;text-transform:uppercase;color:var(--gold-text,var(--gold));margin-bottom:9px}
  .pwhy .sig{display:flex;align-items:center;gap:9px;font-size:14px;padding:4px 0;color:var(--ink)}
  .pwhy .sig .d{width:5px;height:5px;border-radius:50%;background:var(--gold);flex:none}
  .pcta{display:flex;gap:8px;margin-top:13px}
  .pbtn{flex:1;text-align:center;padding:11px 8px;border-radius:var(--radius);font-family:var(--display);font-weight:700;font-size:14px;cursor:pointer}
  /* b31: three buttons on one row; on a narrow phone the first wraps
     to its own row rather than squeezing the label. */
  @media(max-width:420px){.pcta{flex-wrap:wrap}.pcta .pbtn{flex:1 1 44%}.pcta .pbtn:first-child{flex-basis:100%}}
  /* b35: the report already sent for this lead, above the buttons.
     Quiet by design -- it is a fact about the lead, not an action. */
  .prep{display:flex;align-items:center;gap:9px;margin:10px 0 2px;font-size:13.5px;color:rgba(255,255,255,.62)}
  .prep .d{width:5px;height:5px;border-radius:50%;background:var(--gold);flex:none}
  .prep a{color:var(--gold-text,var(--gold));text-decoration:none}
  .prep a:hover{text-decoration:underline}
  .pfull{margin-top:9px;text-align:center;font-size:13px}
  .pfull a{color:var(--gold-text,var(--gold));text-decoration:none}
  .pfull a:hover{text-decoration:underline}
  /* b31: the Map popup. A square map over the card with an X; the card
     stays where it is underneath. */
  .mrpop{position:fixed;inset:0;background:rgba(0,0,0,.72);display:none;align-items:center;justify-content:center;z-index:120;padding:16px}
  .mrpop.on{display:flex}
  /* Width is also capped by the viewport HEIGHT: the map is a square, so
     on a laptop (770px tall, measured) a 720px square plus the header
     would scroll inside the card. min() keeps the whole square in view. */
  .mrpop-card{background:#111114;border:1px solid var(--line);border-radius:12px;width:min(92vw,720px,calc(94vh - 110px));max-height:94vh;overflow:auto;box-shadow:0 24px 60px rgba(0,0,0,.6)}
  .mrpop-hd{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--line)}
  .mrpop-hd b{flex:1;min-width:0;font-family:var(--display);font-size:15px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .mrpop-x{background:none;border:1px solid var(--line);color:var(--ink);border-radius:8px;width:34px;height:34px;font-size:20px;line-height:1;cursor:pointer}
  .mrpop-x:hover{border-color:var(--gold);color:var(--gold-text,var(--gold))}
  .mrpop-map{width:100%;aspect-ratio:1/1;min-height:260px;background:#0b0b0d;border:2px solid #fff;border-radius:0 0 12px 12px;box-sizing:border-box}
  .mrpop-map .mapfallback{display:flex;align-items:center;justify-content:center;height:100%;padding:20px;text-align:center;color:rgba(255,255,255,.7);font-size:14px}
  .mrpop-ft{padding:10px 14px;font-size:13px;color:rgba(255,255,255,.6)}
  .mrpop-ft a{color:var(--gold-text,var(--gold))}
  .pbtn.g{background:var(--gold);color:var(--gold-ink)}
  .pbtn.o{background:#232327;color:var(--ink);border:1px solid var(--line)}
































  .toast{position:fixed;bottom:32px;left:50%;transform:translateX(-50%) translateY(20px);
    background:var(--gold);color:var(--gold-ink);font-family:var(--display);font-weight:800;font-size:14px;
    padding:14px 26px;border-radius:var(--radius);opacity:0;transition:all .3s;z-index:400;white-space:nowrap;
    box-shadow:0 10px 30px rgba(255,204,51,.3)}
  .toast.on{opacity:1;transform:translateX(-50%) translateY(0)}
  .hint{text-align:center;font-size:14px;color:var(--dim);padding:4px 30px 20px;line-height:1.5}
  .hint b{color:var(--gold-text,var(--gold))}
































  .feed{background:linear-gradient(180deg,var(--panel),var(--bg-2));border:1px solid var(--line);border-radius:var(--radius);padding:20px 20px 12px}
  .feed h3{font-family:var(--display);font-weight:900;font-size:17px;margin-bottom:18px}
  /* 🔴 THE LIST CARRIES THE INDENT, NOT THE ITEM. The dot used to be
     positioned inside the same box as the text, from a different origin
     than the rail, so the two drifted apart and the dot landed on the
     timestamp. The item now has NO left padding; the list is indented
     30px and the dot is pulled OUTSIDE it with a negative left. Text and
     dot occupy different boxes, so they cannot collide at any width.
     Rail 4px, dot 0-9px, text from 30px - all measured from the list. */
  .feedlist{position:relative;padding-left:30px}
  .feedlist::before{content:"";position:absolute;left:4px;top:6px;bottom:16px;width:1px;background:rgba(255,204,51,.2)}
  .fitem{position:relative;padding:0 0 18px 0;font-size:14.5px;line-height:1.5}
  .fitem:last-child{padding-bottom:2px}
  .fitem::before{content:"";position:absolute;left:-30px;top:5px;width:9px;height:9px;border-radius:50%;box-sizing:border-box;
    background:var(--gold);box-shadow:0 0 6px rgba(255,204,51,.5);border:2px solid var(--bg-2)}
  /* ⚠ Time on its own line. Inline, a long entry wrapped and pushed the
     timestamp back toward the dot on narrow screens. */
  .fitem .tm{display:block;font-family:var(--display);font-weight:700;font-size:12px;
    letter-spacing:.03em;text-transform:uppercase;color:var(--gold-text,var(--gold));margin-bottom:3px}
  .fitem .ds{display:block;color:var(--dim)}
































  /* ⚠ 26px top gap. The feed and the trend are two different reads and
     they were running together as one block. */
  .trange{margin:10px 0 14px}
  /* ⚠ A NATIVE <select>, not a custom menu - on a phone it opens the OS
     picker, which is the control an agent already knows and the one that
     stays reachable with a screen reader. */
  .trsel{width:100%;padding:10px 34px 10px 13px;border:none;border-radius:10px;cursor:pointer;
    /* u07, 19 Sep 2026: was color:var(--ink) - black text on this dark gradient in light mode. The pill's
       background is fixed, so its text color is too. */
    font-family:var(--body);font-weight:500;font-size:14.5px;color:#f5f5f3;
    background-color:#1e222a;
    background-image:linear-gradient(180deg,#333944 0%,#1e222a 100%),
      url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffcc33' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat:no-repeat,no-repeat;background-position:0 0,right 11px center;
    background-size:100% 100%,12px 12px;box-shadow:0 2px 0 #14171d;
    -webkit-appearance:none;-moz-appearance:none;appearance:none}
  .trsel:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
  /* 🔴 The list is drawn by the OS, so it needs its own colors or it
     renders white-on-white in dark mode on some Android builds. */
  .trsel option{background:#000;color:#f5f5f3}

  /* Dropdown lists are black across every hub page -- the rule and the
     reason live in assets/hub.css. Not repeated here; one copy. */
  .trend{margin-top:26px;background:linear-gradient(180deg,var(--panel),var(--bg-2));border:1px solid var(--line);border-radius:var(--radius);padding:20px 18px 14px}
  .trend h3{font-family:var(--display);font-weight:900;font-size:17px;padding:0 4px}
  .trend .sub{font-size:14.5px;color:var(--dim);padding:2px 4px 10px}
  .trend .legend{display:flex;gap:18px;padding:0 4px 8px;font-size:13px;color:var(--dim)}
  .trend .legend span{display:flex;align-items:center;gap:5px}
  .trend .legend .k{width:14px;height:3px;border-radius:2px}
  .trend svg{width:100%;height:auto;display:block;color:var(--dim)}
  /* u07: axis labels and gridlines take the theme's colors (they were white-on-white in light mode). */
  .trend svg text{fill:currentColor}
  .trend svg line.grid{stroke:var(--line)}
































  .recos{grid-column:1 / -1}
  .recos .rhd{display:flex;align-items:center;gap:9px;font-family:var(--display);font-weight:900;font-size:18px;padding:0 0 16px}
  .recogrid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}
  @media (max-width:900px){ .recogrid{grid-template-columns:1fr} }
  .reco{background:linear-gradient(180deg,var(--card-hi),var(--card-lo));border:1px solid var(--line);
    border-left:3px solid var(--gold);border-radius:var(--radius);padding:18px;display:flex;gap:14px;cursor:pointer}
  .reco .ic{width:38px;height:38px;border-radius:var(--radius);background:rgba(255,204,51,.12);
    display:flex;align-items:center;justify-content:center;flex:none;font-size:18px}
  .reco .rtx .a{font-family:var(--display);font-weight:800;font-size:15px;color:var(--gold-text,var(--gold));margin-bottom:6px}
  .reco .rtx .b{font-size:14px;color:var(--dim);line-height:1.5}
































  /* 🔴 STICKY TO THE BOTTOM, LIKE A PHONE'S OWN NAV. It scrolled away
   *    with the page, so an agent halfway down a lead list had no way
   *    to move without scrolling back up. On a phone this is where the
   *    thumb already is.
   *
   * ⚠ sticky, NOT fixed. GHL wraps page content in transformed
   *   containers and a transformed ancestor makes a fixed child
   *   position against THAT box — which is exactly how the theme
   *   toggle disappeared. Sticky has no such problem.
   */
  /* 🔴 FIXED, NOT STICKY. Sticky scrolls with the content until it
     reaches the viewport edge, so the bar drifted up and down the page.
     A tab bar that moves is not a tab bar. Fixed pins it to the glass.








     🔴 THE PAGE MUST RESERVE THE SPACE. A fixed bar is out of flow, so
     without the padding-bottom on .app below it covers the last card
     and an agent cannot reach the bottom of their own lead list.








     🔴 nowrap. flex-wrap allowed a second row on a narrow phone, which
     doubles the height the padding below is compensating for and hides
     content again. Items shrink instead. */
  /* 🔴 .topnav / .navitem DELETED 5 SEP 2026. The bar lives in
     assets/nav.js and styles itself under .mrbb, so these rules matched
     nothing and were the kind of dead CSS that gets copied forward for
     a year. What they said, because the next bar has to honour it:

       - padding-bottom: calc(Npx + env(safe-area-inset-bottom, 0px))
         The iPhone home indicator sits ON the last row of a fixed
         bottom bar. Without the inset the icons cannot be tapped.
       - flex-wrap: nowrap. Wrapping doubled the bar's height, which
         then no longer matched the padding reserved for it below, and
         the bar covered content again.
       - The nav does not theme to gold on hover, only on .active, so
         the current page is the only thing the eye is drawn to.

     nav.js reproduces all three. It also MEASURES its own height after
     paint instead of hard-coding it, which is what the note on .app
     below used to have to warn about. */
































  .mapsection{grid-column:1 / -1;background:linear-gradient(180deg,var(--panel),var(--bg-2));border:1px solid var(--line);
    border-radius:var(--radius);padding:20px;overflow:hidden}
  .mapsection h3{font-family:var(--display);font-weight:900;font-size:17px;margin-bottom:6px}
  .mapsection .sub{font-size:14.5px;color:var(--dim);margin-bottom:14px}
  .mapcanvas{width:100%;height:420px;border-radius:var(--radius);overflow:hidden;background:var(--card-hi);position:relative}
  .mapcanvas .mapfallback{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    color:rgba(255,255,255,.68);font-family:var(--display);font-weight:800;font-size:14px;text-align:center;
    line-height:1.6;padding:0 20px;letter-spacing:.5px}
































  @media (max-width:768px){
    .topbar{padding:12px 16px}.topbar .wm{font-size:19px}
    .alert{font-size:13px;padding:7px 12px;gap:6px}
    .cosline .coslabel{font-size:13px}.cosline{gap:7px}.topbar .right{gap:12px}
    .maincontent{padding:0 14px;gap:16px;grid-template-columns:1fr}
    .leadcol,.sidebar,.recos,.mapsection{grid-column:1}
    .drawer{grid-column:1 / -1;margin:14px 0 4px}
    .sectionhead{font-size:17px;padding:16px 0 10px;gap:7px}
    .drawer-toggle{padding:12px 14px;font-size:14.5px}
    .drawer-toggle .mini{gap:12px;font-size:13px}
    .drawer-inner{padding:14px;gap:12px;grid-template-columns:1fr 1fr}
    .wcard{padding:14px}.cgauge{width:78px;height:78px}.cgauge .cc .n{font-size:16px}
    .stattiles{grid-template-columns:1fr 1fr;gap:8px}.stile{padding:11px 12px}.stile .val{font-size:19px}
    .lead{padding:15px}.lead .nm{font-size:17px}.lead .ad{font-size:14.5px}
    .score{width:40px;height:40px}.score .circle{width:38px;height:38px;font-size:15px}
    /* 🔴 NO height HERE. The base rule uses aspect-ratio:1 so height
       follows the width the flex row assigns -- four across a phone gives
       four squares. An explicit height beats aspect-ratio and turned them
       straight back into rectangles, which is the trap the base rule's
       own comment warns about for min-height. Same trap, different
       property. Only the icon and label are scaled here. */
    .act svg{width:18px;height:18px}.act .t{font-size:12px;letter-spacing:0} /* 28 Sep: was 13px; labels overran the buttons */
    .propbox{grid-template-columns:1fr}.propsv{min-height:180px}
    .feed,.trend{padding:16px 15px 10px}.feed h3,.trend h3{font-size:15px}
    .mapcanvas{height:280px}
    .recogrid{grid-template-columns:1fr;gap:11px}.reco{padding:14px;gap:11px}
    /* (the .topnav phone overrides moved to assets/nav.js with the bar;
       the no-wrap + hidden-scrollbar pair survived the move intact) */
  }
  @media (max-width:480px){
    .topbar{padding:10px 12px;flex-wrap:wrap;gap:8px}
    .maincontent{padding:0 10px;gap:12px}
    .drawer-inner{grid-template-columns:1fr}
    .stattiles{grid-template-columns:1fr}
    .cgauge{width:64px;height:64px}.cgauge .cc .n{font-size:14px}
    .lead{padding:12px}.lead .nm{font-size:15px}
    .score{width:34px;height:34px}.score .circle{width:32px;height:32px;font-size:14px}
    /* ⚠ Same as above: no height, or the square stops being one. */
    .act svg{width:16px;height:16px}.act .t{font-size:11px;letter-spacing:0} /* 28 Sep: was 13px; "SKIP TRACE" ran past the button edges */
    .mapcanvas{height:220px}
    /* 🔴 THE 16px ICON WAS THE COMPLAINT. This rule is why the bar
       was the hardest thing in the product to hit: a 16px glyph with an
       8px label, on the control used more than any other. nav.js draws
       them at 28px (16 x 1.75) with a 10px label under rather than
       beside, which is what buys the width back. */
    /* NOTE Tighter on a small phone so the heading, the select and
       + Add lead stay on one row rather than wrapping. */
    .viewsel{max-width:150px;font-size:14px}
    .toast{font-size:13px;padding:10px 16px;bottom:18px}
  }
  @media (max-width:360px){
    /* 28 Sep 2026: the smallest phones -- a little less side padding so the longest label still fits */
    .act{padding-left:3px;padding-right:3px}.act .t{font-size:10.5px}
  }
  @media (max-width:340px){
    /* iPhone SE width: the two-word labels take two short lines rather than cross the edge */
    .act .t{white-space:normal;text-align:center;line-height:1.1}
  }
















  /* ══════════════════════════════════════════════════════════════
     LIGHT THEME
     🔴 ONE OVERRIDE BLOCK, NO DUPLICATED RULES. Every surface in the
        dashboard now reads from a token, so the whole interface flips
        by redefining nine values. Nothing below this is theme-aware and
        nothing needs to be.
     ⚠ NOT AN INVERSION. Pure white on a screen an agent stares at for
       an hour is worse than the dark version — the light theme is warm
       off-white with real greys, the way a document reads.
     ══════════════════════════════════════════════════════════════ */
  [data-theme="light"]{
    --bg:#f7f6f4; --bg-2:#f2f1ee; --panel:#ffffff; --panel2:#faf9f7;
    --card-hi:#ffffff; --card-lo:#fdfcfb; --surface:#f4f3f0; --surface-hi:#eceae6;
    --well:#ffffff;
    --line:rgba(24,24,27,.12);
    --ink:#18181b; --dim:rgba(24,24,27,.68);
    /* ⚠ Gold on white fails contrast badly. The accent darkens rather
       than the text lightening — the brand stays, the legibility works. */
    --gold:#ffcc33;--gold-text:#000000; --gold-2:#f0a500; --gold-ink:#0a0a0a;
    --preforeclosure:#c0342c; --fsbo:#1d5fa8; --likely-to-sell:#0f7a6b;
    --expired:#a06000; --probate:#6b3fc4;
    --call:#c02a55; --sms:#1d5fa8; --email:#7a4fc4; --mail:#0f7a6b; --camp:#000000;
    /* Shadows are softer and warmer on light — a hard black shadow on
       off-white reads as dirt. */
    --lift-1:0 1px 2px rgba(24,24,27,.06);
    --lift-2:0 1px 2px rgba(24,24,27,.06), 0 6px 16px -8px rgba(24,24,27,.14);
    --lift-3:0 2px 4px rgba(24,24,27,.08), 0 16px 34px -12px rgba(24,24,27,.2);
  }
  [data-theme="light"] .lead{background:linear-gradient(180deg,#fff,#fdfcfb)}
  [data-theme="light"] .lead:hover{border-color:rgba(169,121,0,.4)}
















  /* The switch itself. ⚠ Sits with the other controls rather than
     floating — a theme toggle is a setting, not a feature. */
  /* 🔴 IN THE TOPBAR, NOT FLOATING. It was position:fixed and vanished —
     GHL wraps page content in transformed containers, and a transformed
     ancestor makes a fixed child position against THAT box rather than
     the viewport. Sitting in real markup removes the whole class of
     problem, and a theme switch belongs with the other controls anyway. */
  .themebtn{flex:none;width:34px;height:34px;border-radius:var(--radius);cursor:pointer;
    background:var(--panel2);border:1px solid var(--line);color:var(--dim);
    display:flex;align-items:center;justify-content:center;
    box-shadow:var(--lift-2);transition:.15s}
  .themebtn:hover{color:var(--gold-text,var(--gold));border-color:var(--gold)}
  .themebtn:active{transform:translateY(1px);box-shadow:var(--lift-1)}
  .themebtn svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:2;
    stroke-linecap:round;stroke-linejoin:round}
  @media(max-width:640px){.themebtn{width:34px;height:34px}}
















  /* View selector — sits in the section heading, sized to its content */
  /* ⚠ Sits on the same row as the view filter, hard right. Deliberately
     quieter than the gold actions on a lead card -- adding a contact is
     an occasional deliberate act, not the thing an agent came here to
     do, and a gold button here would compete with the work. */
  .addlead{margin-left:auto;background:var(--panel2);color:var(--ink);
    border:1px solid var(--line);border-radius:var(--radius);
    font-family:var(--body);font-weight:600;font-size:14px;
    padding:8px 14px;cursor:pointer;white-space:nowrap;flex:none;
    transition:border-color .15s,color .15s}
  .addlead:hover{border-color:var(--gold);color:var(--gold-text,var(--gold))}
  .addlead:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
  @media(max-width:640px){.addlead{font-size:14px;padding:7px 11px}}
  /* CRITICAL: max-width AND min-width:0 TOGETHER, OR NEITHER WORKS. A
     native select sizes itself to its widest OPTION, and a flex child
     defaults to min-width:auto, which refuses to shrink below that
     content width. This clamp is what actually made room for + Add
     lead. Shortening the Hot Leads label did NOT, because the widest
     option is "My Leads - everything sent to me".
     NOTE The full text still shows in the open dropdown -- only the
       closed control truncates. */
  .viewsel{background:var(--panel2);color:var(--ink);border:1px solid var(--line);
    border-radius:var(--radius);padding:5px 26px 5px 10px;font-family:var(--display);
    font-weight:800;font-size:15px;cursor:pointer;
    max-width:200px;min-width:0;flex:0 1 auto;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    appearance:none;-webkit-appearance:none;
    background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffcc33' stroke-width='3'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat:no-repeat;background-position:right 7px center;background-size:11px}
  .leadq{background:var(--panel2);color:var(--ink);border:1px solid var(--line);
    border-radius:var(--radius);padding:6px 11px;font-family:var(--body);
    font-size:14px;max-width:220px;min-width:0;flex:0 1 auto}
  .leadq:focus{outline:none;border-color:var(--gold)}
  @media(max-width:640px){.leadq{max-width:150px;font-size:14px}}
  .viewsel:hover{border-color:var(--gold)}
  .viewsel:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
















  /* Call notes */
  .smsc{display:flex;align-items:flex-start;gap:10px;margin-top:14px;padding:12px 13px;
  border:1px solid rgba(255,204,51,.28);border-radius:7px;background:rgba(255,204,51,.05);
  cursor:pointer}
.smsc input{margin-top:2px;width:17px;height:17px;accent-color:#ffcc33;flex:none}
.smsc span{display:block;font-size:14.5px;line-height:1.45}
.smsc b{display:block;color:#f0f0f4;font-weight:600}
.smsc i{display:block;font-style:normal;font-size:14px;color:rgba(240,240,244,.6);margin-top:3px}
.ntrec{display:flex;gap:10px;align-items:flex-start;cursor:pointer;
    padding:11px;border:1px solid var(--line);border-radius:var(--radius);
    background:var(--panel2)}
  .ntrec input{margin-top:3px;width:16px;height:16px;accent-color:var(--gold);flex:none}
  .ntrec b{display:block;font-size:14px;color:var(--ink)}
  .ntrec i{display:block;font-style:normal;font-size:13px;color:var(--dim);margin-top:2px}
  /* 🔴 The consent script sits in front of the agent as they dial, not
     as something to remember. */
  .ntscript{margin-top:9px;padding:12px 14px;border-left:2px solid var(--gold);
    background:rgba(255,204,51,.06);font-size:14px;color:var(--ink);line-height:1.6}
  .ntscript-n{font-size:13px;color:var(--dim);margin-top:6px}
  .ntmic{display:flex;justify-content:center;margin-top:10px}
  .ntbtn{display:flex;align-items:center;gap:9px;padding:13px 22px;cursor:pointer;
    border-radius:var(--radius);border:1px solid var(--line);background:var(--panel2);
    color:var(--ink);font-family:var(--body);font-size:14px;font-weight:700;
    transition:.14s}
  .ntbtn:hover{border-color:var(--gold);color:var(--gold-text,var(--gold))}
  .ntbtn.on{background:var(--gold);color:#0a0a0a;border-color:var(--gold);
    animation:ntPulse 1.6s ease-in-out infinite}
  @keyframes ntPulse{0%,100%{box-shadow:0 0 0 0 rgba(255,204,51,.5)}
    50%{box-shadow:0 0 0 9px rgba(255,204,51,0)}}
  .nticon{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:2;
    stroke-linecap:round;stroke-linejoin:round}
  @media(prefers-reduced-motion:reduce){.ntbtn.on{animation:none}}
















  /* The AI mark on a button, rather than beside one — it acts on the
     text in this panel, so it belongs in the same row. */
  .aii{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.7;
    stroke-linejoin:round;vertical-align:-2px;margin-right:3px;
    filter:drop-shadow(0 0 3px rgba(255,204,51,.6))}
  #mxTailor{color:var(--gold-text,var(--gold))}
  #mxTailor.busy .aii{animation:aiSpin 1.1s linear infinite;filter:none}
  @keyframes aiSpin{to{transform:rotate(360deg)}}
  @media(prefers-reduced-motion:reduce){#mxTailor.busy .aii{animation:none;opacity:.5}}
















  .editct{color:var(--gold-text,var(--gold));cursor:pointer;font-size:14px;
    text-decoration:underline;text-underline-offset:2px}
  .editct:hover{color:#ffd75e}
















  /* Contacts panel */
  .ctrow{display:flex;align-items:center;gap:10px;padding:9px 0;
    border-bottom:1px solid var(--line)}
  .ctrow:last-child{border-bottom:none}
  .ctv{font-family:monospace;font-size:14.5px;color:var(--ink);flex:none}
  .cttag{font-family:var(--body);font-size:12px;letter-spacing:.1em;text-transform:uppercase;
    background:rgba(255,204,51,.16);color:var(--gold-text,var(--gold));border-radius:3px;
    padding:1px 5px;margin-left:7px;vertical-align:middle}
  .ctm{font-size:13px;margin-left:auto;text-align:right}
  .ctx{background:none;border:none;color:var(--dim);font-size:19px;line-height:1;
    cursor:pointer;padding:0 2px;flex:none;opacity:.5;transition:.12s}
  .ctx:hover{opacity:1;color:var(--preforeclosure)}
  .ctadd{margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}
















  /* ══════════════════════════════════════════════════════════════
     POLISH LAYER — appended deliberately.
     🔴 NOTHING ABOVE THIS LINE WAS RESTRUCTURED. These rules sit last
        so they win on order rather than specificity, which means every
        one can be deleted in a block to revert. No markup moved, no
        handler touched, no class renamed.
     ══════════════════════════════════════════════════════════════ */
















  /* Cards lift. A flat 1px border is legible; depth is what makes
     something feel touchable. */
  .lead{box-shadow:var(--lift-2);
    transition:transform .16s cubic-bezier(.2,.7,.3,1), box-shadow .16s, border-color .16s}
  .lead:hover{transform:translateY(-2px);box-shadow:var(--lift-3);
    border-color:rgba(255,204,51,.26)}
















  /* ══════════════════════════════════════════════════════════════
     RAISED BUTTONS
     🔴 A 1px BORDER IS NOT ELEVATION. Three things together make a
        button look raised, and any one alone does nothing:
          1. a light line along the TOP edge — light falls from above,
             so the top face catches it
          2. a shadow BELOW, cast onto the surface underneath
          3. a slight gradient, because a flat fill reads as painted on
        Remove one and it goes back to looking like a rectangle.
     ⚠ And the press must collapse all three at once. A button that
       moves but keeps its shadow looks like it is sliding, not pressing.
     ══════════════════════════════════════════════════════════════ */
  .act{
    background:linear-gradient(180deg, var(--surface-hi), var(--surface));
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.13),
      0 1px 0 rgba(0,0,0,.5),
      0 2px 5px -1px rgba(0,0,0,.5);
    transition:transform .09s, box-shadow .12s, border-color .15s, filter .15s}
  .act:hover{
    filter:brightness(1.14);
    border-color:rgba(255,255,255,.24);
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.18),
      0 2px 0 rgba(0,0,0,.5),
      0 5px 12px -2px rgba(0,0,0,.6)}
  /* ⚠ Two pixels, not one. One reads as a jitter; two reads as the
     button actually going down. */
  .act:active{
    transform:translateY(2px);
    filter:brightness(.96);
    box-shadow:inset 0 2px 5px rgba(0,0,0,.45)}
















  /* A bright fill needs its highlight INSIDE, or the edge looks dirty. */
  .mx-btn{
    border-radius:12px;color:#000000;
    background:linear-gradient(180deg,#FFDF6B 0%,var(--gold) 100%);
    box-shadow:0 2px 0 #D89308,0 4px 0 #B87C07,0 6px 0 #966405,0 14px 22px rgba(0,0,0,.5);
    transition:transform .08s, box-shadow .08s}
  .mx-btn:hover{transform:translateY(-1px);
    box-shadow:0 2px 0 #D89308,0 4px 0 #B87C07,0 7px 0 #966405,0 18px 26px rgba(0,0,0,.55)}
  .mx-btn:active{transform:translateY(6px);box-shadow:0 2px 6px rgba(0,0,0,.4)}
















  /* ⚠ The secondary is deliberately flatter. If both look equally
     raised, neither is the primary — the point of a hierarchy is that
     the eye lands somewhere without reading. */
  .mx-btn.g{
    background:linear-gradient(180deg, var(--surface-hi), var(--surface));
    box-shadow:inset 0 1px 0 rgba(255,255,255,.13), 0 1px 3px rgba(0,0,0,.4)}
  .mx-btn.g:hover{filter:brightness(1.12);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.13), 0 3px 8px -2px rgba(0,0,0,.5)}
  .mx-btn.g:active{transform:translateY(2px);
    box-shadow:inset 0 2px 5px rgba(0,0,0,.4)}
















  .pbtn{
    background:linear-gradient(180deg, var(--surface-hi), var(--surface));
    box-shadow:inset 0 1px 0 rgba(255,255,255,.13), 0 1px 0 rgba(0,0,0,.5),
               0 2px 6px -2px rgba(0,0,0,.5);
    transition:transform .09s, box-shadow .12s, filter .15s}
  /* 🔴 EXTRUDED SLAB - the three stacked plates ARE the button. They
     are not decoration; drop one and the side wall collapses into a
     flat drop shadow. Keep them in darkening order. */
  .pbtn.g{
    border-radius:12px;
    background:linear-gradient(180deg,#FFDF6B 0%,var(--gold) 100%);color:#000000;
    box-shadow:0 2px 0 #D89308,0 4px 0 #B87C07,0 6px 0 #966405,0 14px 22px rgba(0,0,0,.5)}
  .pbtn.o{
    border-radius:12px;border:none;
    background:linear-gradient(180deg,#333944 0%,#1e222a 100%);color:var(--ink);
    box-shadow:0 2px 0 #232730,0 4px 0 #1c2028,0 6px 0 #14171d,0 14px 22px rgba(0,0,0,.45)}
  .pbtn:hover{filter:none;transform:translateY(-1px)}
  .pbtn.g:hover{box-shadow:0 2px 0 #D89308,0 4px 0 #B87C07,0 7px 0 #966405,0 18px 26px rgba(0,0,0,.55)}
  .pbtn.o:hover{box-shadow:0 2px 0 #232730,0 4px 0 #1c2028,0 7px 0 #14171d,0 18px 26px rgba(0,0,0,.5)}
  /* 🔴 The press must collapse the whole stack. Depth that does not
     flatten on click reads as a sticker, not a control. */
  .pbtn:active{transform:translateY(6px);box-shadow:0 2px 6px rgba(0,0,0,.4)}
















  .themebtn{
    background:linear-gradient(180deg, var(--surface-hi), var(--surface));
    box-shadow:inset 0 1px 0 rgba(255,255,255,.13), 0 2px 5px -1px rgba(0,0,0,.5)}
  .themebtn:active{transform:translateY(2px);
    box-shadow:inset 0 2px 5px rgba(0,0,0,.4)}
















  /* 🔴 LIGHT THEME INVERTS THE LOGIC. On a pale surface the top edge is
     already near-white, so elevation comes from the SHADOW and a darker
     bottom edge — an inset white line would be invisible. */
  [data-theme="light"] .act,
  [data-theme="light"] .pbtn,
  [data-theme="light"] .mx-btn.g,
  [data-theme="light"] .themebtn{
    background:linear-gradient(180deg,#ffffff,#f4f3f0);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.9),
               0 1px 0 rgba(24,24,27,.1),
               0 2px 5px -1px rgba(24,24,27,.12)}
  [data-theme="light"] .act:active,
  [data-theme="light"] .pbtn:active,
  [data-theme="light"] .mx-btn.g:active,
  [data-theme="light"] .themebtn:active{
    box-shadow:inset 0 2px 5px rgba(24,24,27,.16)}
  /* ⚠ Light theme needs its own plate stack. The dark plates are far
     too heavy on a white page and read as a bruise under the button. */
  [data-theme="light"] .mx-btn,[data-theme="light"] .pbtn.g{
    background:linear-gradient(180deg,#FFDF6B 0%,#ffcc33 100%);color:#000000;
    box-shadow:0 2px 0 #D89308,0 4px 0 #B87C07,0 6px 0 #966405,0 10px 16px rgba(24,24,27,.22)}
  [data-theme="light"] .mx-btn-unused{
    background:linear-gradient(180deg,#c08c00,var(--gold));
    box-shadow:inset 0 1px 0 rgba(255,255,255,.35),
               0 1px 0 rgba(24,24,27,.18),
               0 3px 8px -2px rgba(24,24,27,.28)}
















  /* ⚠ Focus was invisible. Keyboard users had no idea where they were,
     which is an accessibility gap before it is a polish one. */
  .act:focus-visible, .mx-btn:focus-visible, .iopt:focus-visible,
  button:focus-visible, a:focus-visible{
    outline:2px solid var(--gold);outline-offset:2px;border-radius:var(--radius)}
















  /* Pills sit tighter to the type. */
  .pill{border-radius:3px;padding:3px 9px;letter-spacing:.5px}
















  .iopt{transition:background .15s, transform .1s}
  .iopt:active{transform:translateY(1px)}
















  /* ⚠ Motion respected. Everything above is decoration; none of it is
     worth making someone unwell. */
  @media (prefers-reduced-motion:reduce){
    .lead, .act, .mx-btn, .iopt{transition:none}
    .lead:hover, .act:active, .mx-btn:active, .iopt:active{transform:none}
  }




  /* ══════════════════════════════════════════════════════════════
     WORKFLOW BUTTONS — convex face, gold hairline
     CSS only. Delete this block to revert exactly; nothing above
     depends on it and no markup or handler changes.
     ══════════════════════════════════════════════════════════════ */
  .act{
    border-radius:9px;
    border:1px solid rgba(255,204,51,.22);
    background:radial-gradient(155% 135% at 50% -32%, #303036 0%, #202025 46%, #131316 76%, #0b0b0d 100%);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.14), 0 6px 16px -9px rgba(0,0,0,.55);
    transition:transform .1s, box-shadow .14s, border-color .15s, filter .15s;
  }
  /* Convex sheen. Inset 1px so it stays inside the corners without
     overflow:hidden, which would clip the lock and query badges that
     sit at top:-4px. */
  .act::before{
    content:"";position:absolute;left:1px;right:1px;top:1px;height:11px;pointer-events:none;
    background:linear-gradient(180deg,rgba(255,255,255,.15),rgba(255,255,255,0));
    border-radius:8px 8px 0 0;
  }
  .act svg, .act .t{position:relative;z-index:2}
  .act:hover{
    filter:brightness(1.06);border-color:var(--gold);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.18), 0 8px 18px -8px rgba(0,0,0,.6);
  }
  /* 🔴 REPLACES scale(.95). A button that shrinks reads as receding;
     one that moves down with an inset shadow reads as pressed. The
     difference matters on the CALL button, which is the one an agent
     needs to feel they actually hit. */
  .act:active{
    transform:translateY(2px);filter:brightness(.97);
    box-shadow:inset 0 2px 6px rgba(0,0,0,.5);
  }
  .act.gated{border-color:rgba(255,255,255,.30)}




  /* ⚠ nonum and locked keep their own opacity and cursor from the
     rules above — the gradient sits under them, so a dimmed button is
     still visibly dimmer than a live one while still looking pressable. */
  .act.nonum, .act.locked{
    box-shadow:inset 0 1px 0 rgba(255,255,255,.08), 0 3px 10px -8px rgba(0,0,0,.5);
  }
  .act.nonum:hover, .act.locked:hover{border-color:rgba(255,204,51,.55)}




  [data-theme="light"] .act{
    background:radial-gradient(155% 135% at 50% -30%, #ffffff 0%, #f6f5f2 55%, #eeece7 100%);
    border-color:rgba(169,121,0,.30);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.9), 0 4px 12px -6px rgba(24,24,27,.18);
  }
  [data-theme="light"] .act::before{
    background:linear-gradient(180deg,rgba(255,255,255,.75),rgba(255,255,255,0));
  }
  [data-theme="light"] .act:active{box-shadow:inset 0 2px 6px rgba(24,24,27,.14)}

  /* ══════════════════════════════════════════════════════════════════
     PUNCHLIST — 15 Sep 2026, from Jason's marked-up screenshots.
     Appended deliberately: later rules of equal specificity win, so each
     item below overrides its base rule without editing it. Delete this
     block to revert the lot.
     ══════════════════════════════════════════════════════════════════ */

  /* [1] DARK — the four action buttons get a gold outline.
         Everything else, rounded corners included, is untouched. */
  .act{border:1px solid rgba(255,204,51,.55)}

  /* [2] DARK — the name chevron. 1.75x of 14px = 24px, and #ffcc33.
     ⚠ The expanded state at :1128 already turns it gold; this makes it
       gold at rest too, so the color no longer signals "open". The
       rotation still does. */
  .lead .nm .chev{font-size:24px;color:#ffcc33}

  /* [3] BOTH — the Hot Leads dropdown arrow, 1.75x of 11px = 19px.
     ⚠ The arrow is an inline SVG data-URI, not a glyph, so its size is
       background-size and its color is the stroke inside the URI. */
  .viewsel{background-size:19px}

  /* ── LIGHT THEME ─────────────────────────────────────────────────── */

  /* [4] LIGHT — page background all white. Only the two canvas layers;
         --surface and --panel stay as they are so buttons and cards keep
         their edges against it. */
  [data-theme="light"]{--bg:#ffffff; --bg-2:#ffffff}

  /* [5] LIGHT — the Overview bar gets a black border. */
  [data-theme="light"] .drawer-toggle{border-color:#18181b}

  /* [6] LIGHT — the dropdown arrow in black. Same SVG, stroke swapped;
         %23 is a URL-escaped '#'. */
  [data-theme="light"] .viewsel{
    background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2318181b' stroke-width='3'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}

  /* [7] LIGHT — lead card border black, rounded corners kept.
     ⚠ .lead.hot sets its own gold border at :1121 and is more specific,
       so the hot cards keep their gold edge. Named here so that reads as
       a decision rather than something missed. */
  [data-theme="light"] .lead{border-color:#18181b}

  /* [8] LIGHT — action button borders black, corners unchanged. This also
         undoes [1] for light, where a gold outline on white is mush. */
  [data-theme="light"] .act{border-color:#18181b}

  /* [9] LIGHT — the score number black on the gold disc.
     ⚠ Targeted at .score.hot .circle rather than the --gold-ink variable,
       which is read in five places; changing the variable would repaint
       text on every gold surface in the product. */
  [data-theme="light"] .score.hot .circle{color:#18181b}

  /* [11] The AI orb now lives in the toolbar row, at its right edge.
     ⚠ .addlead already carries margin-left:auto. A second auto margin here
       would SPLIT the free space between the two instead of pooling it
       behind both, parking the orb mid-row. Zeroed in this context only --
       .cosline keeps its auto margin everywhere else. */
  .sectionhead .cosline{margin-left:0}

  /* [11b] ...which leaves .topbar empty for everyone who is not the owner,
     because #ownerBar and #alertBar are both display:none by default. The
     strip collapses to nothing rather than sitting there as 32px of empty
     sticky chrome; the two bars carry their own vertical margin so they
     still breathe when they do appear. */
  .topbar{padding-top:0;padding-bottom:0}
  #ownerBar{margin:14px 0 10px !important}
  .topbar .alert{margin:14px 0 10px}

  /* [10] LIGHT — signal pill: black plate, #ffcc33 lettering.
     🔴 !important IS LOAD-BEARING HERE. The pill's background is written
        as an INLINE style by the render (var(--likely-to-sell) and the
        rest), and an inline style beats any selector without it.
     ⚠ THIS FLATTENS THE SIGNAL COLOUR CODING IN LIGHT MODE. Pre-foreclosure
       red, FSBO blue, likely-to-sell teal, expired amber and probate purple
       all become the same black plate, so the color stops telling you
       which signal fired — only the words do. That is what the markup
       asked for; flagged because it is an information change, not a
       paint change. */
  [data-theme="light"] .pill{background:#18181b !important;color:#ffcc33}

