/* admin/css/50-guide-feed-phases.css: The guide, the photo feed, phases 12 to 14 (call list, crew, customer account).
   The admin stylesheet is these files in numeric order, linked from admin.html; a later file overrides an earlier one, so keep the order. */
/* ---------- the guide: a walkthrough of the real dashboard ----------
   The tour drives the page instead of describing it, so the chrome is a hole
   rather than a dialog: a veil that swallows every click, a spotlight whose
   own box-shadow paints the dim everywhere except inside itself, and a card
   pinned beside the subject. Three z-index facts it depends on: the lead
   panel is 61, the sheet scrim is 80, and 70 is the one slot between them,
   so the tour dims an open panel and still sits under a confirm sheet. */
/* WHERE YOU ARE STAYS IN SIGHT (2026-09-30). The owner: "i dont like how the
   tutorial/walkthrough makes the rest of the page so dark, its hard to see
   what tab or page its on." The dim was 82% black over everything, the menu
   and the page title included. Now it is a lighter dim over the PAGE only:
   the rail, the topbar, the preview bar and the phone's tab bar are lifted
   above it (`html.touring`, still unclickable), and the ring and the card sit
   above them. Four layers, so `.tour` is `display:contents` and makes no
   stacking context of its own: 70 the dim and the click blocker, 72 the
   chrome, 73 the ring, 74 the card. 70 is still the slot between the lead
   panel (61) and a sheet's scrim (80). */
.tour{display:contents}
/* the click blocker. A walkthrough is read only: the spotlit control is as
   unclickable as everything else, so a tour can never send a text or mark a
   job paid. The lifted chrome lets clicks through to it. */
.tour-veil{position:fixed;inset:0;z-index:70;background:transparent;pointer-events:none;transition:background .2s var(--ease)}
.tour.open .tour-veil{pointer-events:auto}
.tour.open.no-spot .tour-veil{background:rgba(3,8,5,.58)}
/* The hole. A spread the size of the screen paints the dim OUTSIDE the box,
   which is what makes this one element rather than four. */
.tour-spot,.tour-ring{position:fixed;top:0;left:0;width:0;height:0;border-radius:12px;pointer-events:none;opacity:0;
  transition:opacity .2s var(--ease),top .3s var(--ease),left .3s var(--ease),width .3s var(--ease),height .3s var(--ease)}
.tour-spot{z-index:70;box-shadow:0 0 0 max(200vw,200vh) rgba(3,8,5,.5)}
/* the ring is its own layer, above the chrome, so a step about the menu
   still shows what it is pointing at */
.tour-ring{z-index:73;box-shadow:0 0 0 1.5px var(--blaze-hot),0 0 22px 2px rgba(255,106,36,.3)}
.tour.open .tour-spot,.tour.open .tour-ring{opacity:1}
/* a step that moves the page under the hole must not animate the hole too, or
   it lags a third of a second behind what it is pointing at */
.tour-spot.jump,.tour-ring.jump{transition:opacity .2s var(--ease)}
.tour.no-spot .tour-spot,.tour.no-spot .tour-ring{opacity:0}
html.touring #rail,html.touring #topbar,html.touring #viewBar,html.touring #tabbar{z-index:72;pointer-events:none}

.tour-card{position:fixed;z-index:74;width:min(420px,calc(100vw - 28px));background:var(--card-2);border:1px solid var(--line-2);
  border-radius:var(--r);box-shadow:var(--shadow-float);padding:15px 18px 14px;
  opacity:0;transform:translateY(6px);transition:opacity .22s var(--ease),transform .22s var(--ease)}
/* The card does NOT slide between steps. It re-fades in place, because the
   spotlight is already travelling and two things moving at once reads as
   drift rather than as a step; it also kept a test clicking Next while the
   button was still settling. */
.tour-card.in{opacity:1;transform:none}
.tour-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:8px}
.tour-chapter{font-size:11.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--blaze-hot)}
.tour-art{margin:0 0 12px}
.tour-art svg{width:100%;height:auto;display:block;border-radius:8px;border:1px solid var(--line)}
.tour-card h2{font-size:19px;letter-spacing:-.02em;margin:0 0 7px;line-height:1.22}
.tour-text{font-size:14.5px;line-height:1.62;color:var(--slate);margin:0}
/* what matters on the screen, so one card covers it (2026-10-13) */
.tour-points{list-style:none;margin:10px 0 0;padding:10px 0 0;border-top:1px solid var(--line);display:grid;gap:7px}
.tour-points[hidden]{display:none}
.tour-points li{position:relative;padding-left:15px;font-size:13.5px;line-height:1.5;color:var(--slate)}
.tour-points li::before{content:"";position:absolute;left:1px;top:.6em;width:5px;height:5px;border-radius:50%;background:var(--blaze-hot)}
.tour-foot{margin-top:14px}
.tour-bar{height:3px;border-radius:2px;background:rgba(255,255,255,.09);overflow:hidden;margin-bottom:11px}
.tour-bar i{display:block;height:100%;background:var(--blaze-hot);border-radius:2px;transition:width .3s var(--ease)}
.tour-row{display:flex;align-items:center;gap:12px}
.tour-count{font-size:12.5px;color:var(--mist);font-weight:600;white-space:nowrap}
.tour-acts{margin-left:auto;display:flex;gap:8px}
.tour-acts .btn{padding:8px 14px;font-size:13.5px}

/* A phone gets a sheet along the bottom, and the subject is scrolled into the
   half of the screen the sheet does not cover (see scrollTo's botRoom). */
@media(max-width:860px){
  /* the sheet stands on the tab bar, not over it (`--tour-bottom`, set in place()) */
  .tour-card{left:0!important;right:0;top:auto!important;bottom:var(--tour-bottom,0px);width:100%;max-height:min(62svh,calc(100svh - var(--tour-bottom,0px) - 140px));overflow:auto;
    border-radius:14px 14px 0 0;border-bottom:none;padding:14px 16px;transform:translateY(14px)}
  /* a subject low on a short page cannot be scrolled clear of the sheet, so
     the sheet moves instead (see `clash` in place()) */
  .tour-card.at-top{top:var(--tour-top,0px)!important;bottom:auto;border-radius:0 0 14px 14px;border-top:none;border-bottom:1px solid var(--line-2);
    padding:12px 16px 14px;transform:translateY(-14px)}
  .tour-card.at-top.in{transform:none}
  .tour-card h2{font-size:18px}
  .tour-text{font-size:14px;line-height:1.55}
  .tour-points{margin-top:8px;padding-top:8px;gap:5px}
  .tour-points li{font-size:13px;line-height:1.45}
  .tour-acts{width:100%;margin-left:0}
  .tour-acts .btn{flex:1;justify-content:center;min-height:44px}
  .tour-row{flex-wrap:wrap}
  .tour-count{order:-1;flex-basis:100%}
}
.guide-card{display:flex;flex-wrap:wrap;gap:8px}
@media(prefers-reduced-motion:reduce){.tour-veil,.tour-card,.tour-spot,.tour-ring,.tour-bar i{transition:none}}

/* ---------- the photo feed (marketing) ---------- */
.feed-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}
.fcard{border:1px solid var(--line);border-top-color:rgba(255,255,255,.13);border-radius:var(--r);overflow:hidden;background:var(--card);cursor:pointer;
  transition:border-color .15s,transform .15s var(--ease),box-shadow .15s;display:flex;flex-direction:column;box-shadow:0 1px 1px rgba(0,0,0,.25)}
@media(hover:hover){.fcard:hover{border-color:var(--line-2);transform:translateY(-1px);box-shadow:0 2px 2px rgba(0,0,0,.25),0 18px 34px -22px rgba(0,0,0,.95)}}
.strip{display:grid;grid-template-columns:1fr 1fr;gap:2px;aspect-ratio:2/1;background:rgba(255,255,255,.04)}
.strip>div{position:relative;overflow:hidden;background:rgba(255,255,255,.03);display:grid;place-items:center}
/* The photo fills its cell and gives it no size: in flow, a portrait photo's
   own height grew the strip past 2:1 (an aspect-ratio box keeps
   min-height:auto), and one card in a row stood 44px taller than the others. */
.strip img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.strip .lbl{position:absolute;left:8px;top:8px;font-size:11.5px;font-weight:600;background:rgba(5,12,8,.8);color:var(--ink);padding:2px 7px;border-radius:4px}
.strip .none{font-size:12px;font-weight:600;color:var(--mist)}
.fcard .body{padding:14px 15px 16px;display:flex;flex-direction:column;gap:7px}
.fcard h3{font-size:15.5px}
.fcard .meta{display:flex;gap:6px 12px;flex-wrap:wrap;font-size:13px;color:var(--slate)}
.fcard .flags{display:flex;align-items:center;gap:6px;margin-top:2px;font-size:12.5px;font-weight:600;color:var(--blaze-hot)}
.fcard .flags .ic{width:14px;height:14px;flex:none}

/* ---------- phases 12 to 14: the call list, self-performed work, a customer's account ----------
   New components only. Nothing here restates a value set above. */
.band-cust{color:var(--t-moss);border-color:rgba(111,203,136,.4)}
.band-own{color:var(--t-kraft);border-color:rgba(199,184,143,.4)}
.lead-row .who .band+.band{margin-left:6px}
.lead-row .meta .good,.crew-load .good,.ih-sub .good{color:var(--t-moss)}
.row-pick{display:inline-flex}
.row-pick .select{width:auto;min-width:168px;padding:8px 32px 8px 12px;font-size:13.5px;min-height:38px}
.btn-text{font:inherit;font-size:13.5px;font-weight:600;color:var(--mist);background:none;border:0;padding:10px 4px;cursor:pointer;text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--line-2)}
@media(hover:hover){.btn-text:hover{color:var(--ink)}}
.btn-ghost.is-on{color:var(--t-moss)}

/* a sheet that may not be walked away from says so by moving, not by shouting */
@keyframes sheet-nudge{0%,100%{transform:none}25%{transform:translateX(-7px)}60%{transform:translateX(5px)}}
.scrim.open .sheet.nudge{animation:sheet-nudge .3s var(--ease)}
@media(prefers-reduced-motion:reduce){.scrim.open .sheet.nudge{animation:none;outline:2px solid var(--blaze-hot)}}

/* the call */
.call-sheet{display:flex;flex-direction:column;gap:18px}
.call-sheet h3{font-size:14.5px;color:var(--slate);font-weight:600;margin:0 0 9px}
.call-top{display:flex;gap:8px;flex-wrap:wrap}
.call-dial{justify-content:center;font-size:17px;padding:15px 18px}
.call-facts{display:grid;gap:12px;margin:0;padding:14px 0;border-block:1px solid var(--line)}
.call-facts div{display:grid;grid-template-columns:96px minmax(0,1fr);gap:12px;font-size:14.5px;line-height:1.5}
.call-facts dt{color:var(--mist)} .call-facts dd{margin:0;color:var(--ink)}
.call-log{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.call-log li{padding:12px 0;border-top:1px solid var(--line)}
.call-log li:first-child{border-top:none;padding-top:0}
.call-when{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;font-size:14.5px}
.call-when b{color:var(--ink)} .call-when span{color:var(--mist);font-size:13px}
.call-note{margin:6px 0 0;font-size:14px;line-height:1.5;color:var(--slate)}
.call-none,.call-more{font-size:14px;margin:0}
.call-more{margin-top:10px}
.call-ask{font-size:16px!important;color:var(--ink)!important}
.call-outcomes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}
.call-outcomes .btn{justify-content:center;padding:13px 12px}
.call-outcomes .btn:first-child{grid-column:1/-1;padding:15px 12px;font-size:16px}
.call-skip{display:block;margin:12px auto 0}
.call-sheet .field-err{margin:10px 0 0}
.book-form{display:flex;flex-direction:column;gap:16px}
.book-form .field-note b{color:var(--ink);font-size:14px}
.who-works{border:0;padding:0;margin:0;min-width:0}
.who-works legend{font-size:13.5px;font-weight:600;color:var(--slate);padding:0;margin-bottom:7px}
.seg-btn.plain::before{display:none}
.seg-btn .ic,.seg-pick .ic{width:15px;height:15px}
.seg-pick{position:relative;display:inline-flex;flex:1 1 180px}
.seg-pick input{position:absolute;opacity:0;inset:0;width:100%;height:100%;margin:0;cursor:pointer}
.seg-pick span{display:flex;flex:1;align-items:center;justify-content:center;gap:8px;font-size:14px;font-weight:600;padding:12px 13px;border-radius:var(--r-sm);border:1px solid var(--line);color:var(--slate);transition:background .15s,color .15s,border-color .15s}
.seg-pick input:checked+span{background:var(--ink);border-color:var(--ink);color:var(--g0)}
.seg-pick input:focus-visible+span{outline:2px solid var(--blaze-hot);outline-offset:2px}
/* a list of answers read top to bottom (the decline reasons): one per line, left aligned */
.seg-col{flex-direction:column}
.seg-col .seg-pick{flex:none}
.seg-col .seg-pick span{justify-content:flex-start}

/* the call list */
.calls-bar .sort .select{min-width:210px}
/* Call list: the list's size sits beside the service it counts, not
   centered between the select and the chips */
.calls-bar .cl-caption{margin-right:auto}
.call-row .who a+.call-st{margin-left:8px;vertical-align:2px}
.call-st{gap:6px}
.call-st::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--mist);flex:none}
.call-st.is-not_contacted::before{background:var(--st-new)} .call-st.is-contacted::before{background:var(--st-contacted)}
.call-st.is-booked::before{background:var(--st-approved)} .call-st.is-declined::before{background:var(--st-lost)}
.call-row .call-last{color:var(--mist);font-size:13.5px}
.call-row .call-said{font-style:italic;color:var(--slate);font-size:13.5px;max-width:70ch}
.cv-calls-body{padding-bottom:4px}
.cv-portal-grid{align-items:start}

/* self-performed: the tool list, the crew */
.toollist .tool-extra{color:var(--mist);font-size:12.5px;font-weight:500;margin-left:6px}
.toollist .ck-meta{display:inline-flex;align-items:center;justify-content:flex-end;gap:6px;max-width:none}
.tool-keep{white-space:nowrap}
.tool-del{width:34px;height:34px;color:var(--mist)}
.tool-add{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;margin-top:12px}
.sp-crew,.sp-notes{margin-top:16px}
/* a contractor for part of the job */
.sp-sub{margin-top:16px}
.sp-sub .field-note{margin-top:0}
.sp-sub .person{margin-top:4px}
.sp-part{margin-top:10px}
.offer-part{margin-top:6px;font-size:14.5px;line-height:1.5}
.sp-cap{margin:0 0 14px;font-size:14px}
.sp-nocrew{margin-top:14px}
.chip[disabled]{opacity:.45;pointer-events:none}
.ih-row .ih-sub{font-size:13.5px;color:var(--mist);margin-top:6px}
/* the band chip's gap: 4px here and the space before it, so the dot does not hug the name */
.ih-row .who>a+.status-chip{margin-left:4px}
/* with Open the job gone a row carries Map
   (and Inspect on a finished job), each its own size on a phone rather than
   a bar the width of the screen. */
@media(max-width:680px){.ih-row .row-actions{display:flex;flex-wrap:wrap;gap:10px}.ih-row .row-actions .btn{width:auto;flex:0 0 auto}}
.crew-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(320px,100%),1fr));gap:12px}
a.jobcard{display:block;text-decoration:none;color:inherit}
.crew-when{display:flex;align-items:center;gap:7px;margin:6px 0 0;font-size:14px;font-weight:600;color:var(--wheat)}
.crew-when.unset{color:var(--slate);font-weight:500}
.crew-when .ic{width:15px;height:15px;flex:none}
.crew-card .meta{margin-top:8px}
.crew-load{margin-top:10px!important}
.crew-load span{display:inline-flex;align-items:center;gap:6px}
.crew-load .ic{width:14px;height:14px}
.crew-body>*+*{margin-top:14px}
.crew-asked{margin:0;font-size:15px;line-height:1.55;color:var(--ink);white-space:pre-wrap;overflow-wrap:anywhere}
.crewjob .cv-acts .btn{flex:1 1 150px;justify-content:center}

/* the customer's account */
.my-services{display:flex;flex-direction:column}
.my-svc{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;align-items:center;padding:16px 0;border-top:1px solid var(--line)}
.my-svc:first-child{border-top:none;padding-top:4px}
.my-svc .who b{font-size:16.5px;color:var(--ink)}
.my-svc .meta{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:14px;color:var(--slate);margin-top:7px}
.my-next{display:flex;flex-direction:column;gap:5px;text-align:right}
.my-next-lbl{font-size:12.5px;color:var(--mist)}
.my-next b{font-family:var(--display);font-size:17px;color:var(--ink);font-weight:600}
.my-next small{font-size:13px;color:var(--mist)}
.my-more-body{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
.my-more-body h2{font-size:19px;margin:8px 0 8px}
.my-more-body .sub{max-width:52ch}
.my-contact-body .sub{margin-bottom:14px}
.my-ba{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}
.my-ba-col>.kicker{display:block;margin-bottom:9px}
.my-pad{padding:4px 0}
/* a month's statement is a list of lines, one figure each, so it reads at 320px */
.my-lines{list-style:none}
.my-line{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 16px;align-items:baseline;padding:14px 0;border-top:1px solid var(--line)}
.my-line:first-child{border-top:0;padding-top:2px}
.my-line-what{display:flex;flex-direction:column;gap:4px;min-width:0}
.my-line-what b{color:var(--ink);font-weight:600;overflow-wrap:anywhere}
.my-line-calc{color:var(--slate);font-size:14px}
.my-line-total{color:var(--ink);font-weight:700;text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}
.my-line-total.is-credit{color:var(--t-moss)}
.my-line-sum{border-top-color:var(--line-2);color:var(--ink);font-weight:700}
.my-lines .my-days{display:block;margin-top:5px;color:var(--mist);font-size:12.5px;line-height:1.5;white-space:normal}
/* The catalog (2026-10-09): one service a row, and the whole row is the button:
   the name on the left, "Ask for a quote" on the right. Hairlines between,
   no box per service. Big type and a 64px target at every width. */
.cat-list{display:flex;flex-direction:column}
.cat-row{display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%;min-height:64px;margin:0;padding:14px 0;
  border:0;border-top:1px solid var(--line);background:none;color:var(--ink);font:inherit;text-align:left}
.cat-row:first-child{border-top:0}
button.cat-row{cursor:pointer;transition:background .14s}
.cat-row b{flex:1 1 auto;min-width:0;font-size:16px;font-weight:600;line-height:1.3;color:var(--ink)}
.cat-ask,.cat-note{flex:none;display:inline-flex;align-items:center;gap:8px;font-size:15px;font-weight:600;white-space:nowrap}
.cat-ask{color:var(--ink)}
.cat-ask .ic{width:18px;height:18px;color:var(--blaze-hot)}
.cat-note{color:var(--slate)}
.cat-note .ic{width:16px;height:16px}
.cat-row.is-have .cat-note{color:var(--t-moss)}
@media(hover:hover){button.cat-row:hover{background:rgba(255,255,255,.035)} button.cat-row:hover .cat-ask{text-decoration:underline;text-underline-offset:4px}}
button.cat-row:focus-visible{outline:2px solid var(--blaze-hot);outline-offset:-2px;border-radius:var(--r-sm)}
.easy .cat-row{min-height:72px;padding:16px 0}
.easy .cat-row b{font-size:19px}
.easy .cat-ask,.easy .cat-note{font-size:var(--fs-lbl)}
@media(max-width:860px){.easy .cat-row b{font-size:18.5px}}

/* suggested services */
.sg-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:16px;align-items:end;padding:16px 0;border-top:1px solid var(--line)}
.sg-row:first-of-type{border-top:none}
.sg-from{margin-top:8px;font-size:13.5px}
.sg-acts{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}
.sg-acts .select{width:auto;min-width:190px;padding:8px 32px 8px 12px;font-size:13.5px;min-height:38px}

/* ============================================================================
   WIDE (1400px and up): fill the screen with two columns, not one and a void
   A stack of folds is a list, and a list 1,700px wide with a 200px title on
   each line is mostly emptiness. From 1400px the stacks that are lists of
   independent boxes are dealt into two columns (ui.js dealColumns, so an
   opened fold only grows its own column), the pipeline's stages grow to meet
   the edge, customer cards and jobs sit two across, and the lead panel is wider.
   ============================================================================ */
@media(min-width:1400px){
  /* NOT CSS columns: WebKit left the whole second column blank (see
     dealColumns). Two real columns, each a stack of its own. What spans the
     page (Today's empty state, Billing's warning, Team's figures) stays
     outside them; a group that never folds is a group like any other and
     belongs IN a column, or one row of a name and three buttons is stretched
     across 1,700px of ground. */
  .today .stack,.billing .stack,.customer .stack,.team.stack{gap:14px}
  .dealt{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:start}
  .dealt-col{display:flex;flex-direction:column;gap:14px;min-width:0}
  /* the gaps space the boxes, not their own margins (Settings' panels kept
     12px of theirs, 26px apart; the team's figures 26px, 40px above) */
  .dealt>.dealt-col>*,[data-deal]>*{margin-top:0;margin-bottom:0}
  /* each box is measured at the width of one column before it is dealt */
  [data-deal].dealing{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:14px;align-items:start}
  /* a redraw can deal a box into the other column: scroll anchoring would
     chase it and move the page under the reader */
  [data-deal]{overflow-anchor:none}
  /* seven stages share the width instead of standing at 264 and scrolling:
     a 1,900px screen holds all of them, a narrower one scrolls at 200 */
  .pipeline .col{flex:1 1 0;min-width:200px}
  .lead-panel{width:min(680px,100%)}
  .lp-actions{gap:8px}
  #cuList{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:12px;align-items:stretch}
  #jbList{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:start}
  #cuList .jobcard,#jbList .jobcard{margin-bottom:0}
  .contractors .cgrid{grid-template-columns:repeat(auto-fill,minmax(360px,1fr))}
  /* the month and the day side by side: the agenda was below 1,100px of grid,
     which is a screen nobody scrolls to for the one thing happening today */
  .calendar{display:grid;grid-template-columns:minmax(0,1fr) clamp(300px,24vw,420px);grid-template-rows:auto 1fr;gap:0 16px;align-items:start}
  .calendar .cal-tools{grid-column:1/-1}
  .calendar .agenda{margin-top:0;position:sticky;top:calc(var(--topbar) + 16px);max-height:calc(100svh - var(--topbar) - 48px);overflow:auto;overscroll-behavior:contain}
  .cal .day{min-height:132px}
  .chart-wrap{height:280px}
  .reports .kpis{grid-template-columns:repeat(6,minmax(0,1fr))}
  .kpis{grid-template-columns:repeat(4,minmax(0,1fr))}
  .stats .kpis{grid-template-columns:repeat(4,minmax(0,1fr))}
  /* A GRID, not CSS columns. WebKit painted the columns version wrong: with
     the offers and the insurance notice set to column-span:all, Under way and
     Finished were laid out at the notice's own top and drawn over it and over
     each other (measured at 1401, 1440 and 1920; Chromium was fine). Two
     panels side by side is all this page ever needed, and a grid keeps each
     child's own display, so nothing here has to re-assert a flex row. */
  .role-contractor .portal-jobs .stack{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:start}
  .role-contractor .portal-jobs .stack>.notice,.role-contractor .portal-jobs .stack>.cj-offers,.role-contractor .portal-jobs .stack>:only-child{grid-column:1/-1}
  /* A grid for the same reason as the jobs stack above. Under CSS columns
     WebKit would not scroll the window back up this page: the guide's step on
     the month's total called scrollBy and nothing moved, so its card sat 226px
     above the top of the screen at 1440 and 1920 (a WebKit multicol fault;
     Chromium and every width under 1400 were fine). */
  .route .stack{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:start}
}
/* the QuickBooks pairs on Reports, one above the other while the rail leaves
   half a panel narrower than the customers table's 274px (234 at 861) */
@media(min-width:861px) and (max-width:1023px){ #rpQb .grid-2{grid-template-columns:minmax(0,1fr)} }
/* a tablet gets the pairs that fit: two customer cards, two contractor cards, two-column forms */
@media(min-width:861px) and (max-width:1399px){
  /* a six column table in a half width cell scrolls sideways to read a name:
     the people tables get the whole width until there is room for two */
  #rpPeople{grid-template-columns:minmax(0,1fr)}
  #cuList{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:12px;align-items:stretch}
  #cuList .jobcard{margin-bottom:0}
}

/* ============================================================================
   responsive
   ============================================================================ */
/* six 42px figures need about 1,500px of page; below that the strip wraps, and a figure is never cut */
@media(max-width:1640px){ .nums{--n:3} }
/* between 861 and 1180 the rail takes 248px and three 42px figures no longer
   fit the rest: $19,550 was being cut to $19,... at 900 */
@media(min-width:861px) and (max-width:1180px){ .nums{--n:2} }
@media(max-width:1180px){ .nums.four,.nums.five{--n:2} }
@media(max-width:1180px){
  .kpis,.reports .kpis{grid-template-columns:repeat(2,minmax(0,1fr))}
  .kpi:nth-child(2n+1){border-left:0}
  .kpi:nth-child(n+3){border-top:1px solid var(--line)}
  .grid-3{grid-template-columns:repeat(2,minmax(0,1fr))}
  .td-open,.th-open,.td-stage,.th-stage{display:none}
  .leads .table-wrap{display:none}
  .leads .cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;align-items:start}
  .leads .lead-name .nm{white-space:normal}
}
/* A LAPTOP HOLDS THE LEADS TABLE. Seven columns wanted 1,091px and a 1280
   screen gives the panel 918, so Received was cut at "Rec" and Value and Open
   sat out of sight behind a sideways scroll (1440 gave 1,078). Measured, not
   guessed: a tighter cell, a stage label that wraps and a shorter next step
   bring it to 970 (fits from 1,332px); under 1,420 the email ellipsizes at
   the width of the phone above it instead of holding the column open (904,
   fits from 1,266); under 1,340 the stage moves under the status and its own
   column goes (755, fits the 819 of 1,181). Names stay on one line, money is
   never cut, and Open stays: it is the keyboard's way into a lead. */
@media(min-width:1181px) and (max-width:1499px){
  .leads .table thead th,.leads .table tbody td{padding-left:8px;padding-right:8px}
  .leads .td-stage{min-width:140px}
  .leads .lead-next{min-width:100px}
}
@media(min-width:1181px) and (max-width:1419px){ .leads .lead-email{width:0;min-width:100%;max-width:none} }
@media(min-width:1181px) and (max-width:1339px){
  .leads .td-stage,.leads .th-stage{display:none}
  .leads .status-stage{display:block}
}
@media(min-width:681px) and (max-width:1023px){ main#view{overflow-x:clip} }
@media(max-width:1023px){
  .fold-head,.og-head{padding:15px 16px}
  .fold-body>*{padding-left:16px;padding-right:16px}
  .fold-body>.lead-row{padding-left:16px;padding-right:16px}
  .fold-body>.tpl-card .tpl-head,.fold-body>.tpl-card .tpl-body{padding-left:16px;padding-right:16px}
  .panel:not(.fold):not(.group-open){padding:18px 16px}
}
@media(max-width:860px){
  .shell{grid-template-columns:minmax(0,1fr)}
  #rail{display:none}
  #tabbar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:50;justify-content:space-around;align-items:stretch;padding:6px 6px calc(6px + env(safe-area-inset-bottom));background:rgba(11,21,16,.92);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-top:1px solid var(--line)}
  #tabbar .navlink{flex:1 1 0;flex-direction:column;gap:4px;font-size:11.5px;padding:7px 4px;min-height:50px;justify-content:center;border-radius:8px;font-weight:500}
  #tabbar .navlink .ic{width:20px;height:20px}
  #tabbar .navlink.active{background:none;color:var(--ink);font-weight:600}
  /* the rail's 3px "where you are" stroke is drawn 14px left of the link; in a five tab bar that is on top of the neighbor */
  #tabbar .navlink.active::before{display:none}
  #tabbar .navlink span{white-space:nowrap}
  #tabbar .navlink .badge{position:absolute;top:4px;right:calc(50% - 22px);margin:0;min-width:18px;height:18px;font-size:10.5px}
  .main{padding-bottom:calc(var(--tabbar) + env(safe-area-inset-bottom))}
  main#view{padding:18px 14px 40px}
  .view-switch{padding:14px 14px 0}
  .has-switch main#view{padding-top:14px}
  /* a row you can swipe when the place has more views than fit */
  .vs{display:flex;width:100%;overflow-x:auto;scrollbar-width:none}
  .vs::-webkit-scrollbar{display:none}
  .vs-btn{flex:1 0 auto}
  #topbar{padding:0 14px;padding-top:env(safe-area-inset-top);height:calc(var(--topbar) + env(safe-area-inset-top))}
  /* a preview puts the notch's inset on the bar above instead */
  .viewbar{padding:env(safe-area-inset-top) 14px 0;height:calc(var(--viewbar) + env(safe-area-inset-top))}
  .viewing #topbar{top:calc(var(--viewbar) + env(safe-area-inset-top));padding-top:0;height:var(--topbar)}
  .vb-switch,.vb-one{display:none}
  .vb-two{display:flex}
  /* the title keeps its word and the search takes the squeeze: at 320
     "Self-Performed" was cut by 4px while the box beside it had room */
  #topbar h1{font-size:17px;flex-shrink:0}
  #topbar .search{flex:1 1 120px}
  #topbar .search kbd{display:none}
  #addLeadBtn span{display:none}
  /* flex:none, or the squeeze reaches the button too: 40px of a 44px target on Self-Performed at 320 */
  #addLeadBtn{width:40px;height:40px;padding:0;border-radius:50%;flex:none}
  @media(pointer:coarse){#addLeadBtn{width:44px;height:44px}}
  .grid-2,.grid-3{grid-template-columns:minmax(0,1fr)}
  .lead-panel{width:100%;border-left:none}
  .lp-actions{grid-template-columns:repeat(5,minmax(0,1fr));gap:6px}   /* auto-fit wrapped 4+1 at 320, leaving Note alone */
  .lp-actions .act{padding:10px 4px;font-size:11.5px}
  .lp-actions .act .ic{width:19px;height:19px}
  .lp-title h2{font-size:19px}
  .lp-title .sub span+span::before{display:none}
  .form-grid{grid-template-columns:minmax(0,1fr)}
  .scrim{align-items:end;padding:0}
  .sheet,.sheet.wide{width:100%;max-height:92svh;border-radius:14px 14px 0 0;border-bottom:none;transform:translateY(20px)}
  .sheet-body{padding-bottom:calc(22px + env(safe-area-inset-bottom))}
  .sheet-body .sheet-actions:last-child,.sheet-body>form:last-child>.form-actions:last-child,.sheet-body>.form-actions:last-child{bottom:calc(-22px - env(safe-area-inset-bottom));margin-bottom:calc(-22px - env(safe-area-inset-bottom));padding-bottom:calc(22px + env(safe-area-inset-bottom))}
  .lead-row{grid-template-columns:minmax(0,1fr);gap:10px}
  .lead-row .who a{font-size:15.5px}
  .lead-row .meta{font-size:13.5px;row-gap:5px}
  .lead-row .row-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(104px,1fr));gap:8px;width:100%;margin-top:2px}
  .lead-row .row-actions .btn{width:100%;padding:10px 8px;font-size:13.5px}
  .lead-row .row-actions .row-pick,.lead-row .row-actions .row-pick .select{width:100%;min-width:0}
  .row-actions{justify-content:flex-start}
  .only-phone{display:block}
  .only-desktop{display:none}
  .icon-btn .only-phone{display:inline-block}
  html.panel-open,html.panel-open body{overflow:hidden}
  [data-sec=next] .quick .btn{flex:1 1 calc(50% - 4px)}
  .fact b{overflow-wrap:anywhere}
  .n-val{font-size:min(32px,15cqi)}
  .num-item{padding:16px 16px 15px}
  .today-head{margin-bottom:18px}
  .today-head h2{font-size:26px}
}
@media(max-width:760px){
  .bl-table th,.bl-table td{padding:9px 12px}
  .bl-tools #blExport{width:100%}
  .bl-acts{padding:0 12px 14px}
  .bl-acts .btn{flex:1 1 auto}
  .numbers .grid-2{grid-template-columns:minmax(0,1fr)}
  .fn-lbl{font-size:13.5px}
}
@media(max-width:680px){
  .leads .cards{grid-template-columns:minmax(0,1fr);gap:8px}
  .lead-name .nm{white-space:normal}
  .panel:not(.fold):not(.group-open){padding:16px 15px}
  .fold-head,.og-head{padding:14px 15px}
  .fold-body>*{padding-left:15px;padding-right:15px}
  .fold-body>.lead-row{padding-left:15px;padding-right:15px}
  .fold-body>.tpl-card .tpl-head,.fold-body>.tpl-card .tpl-body{padding-left:15px;padding-right:15px}
  .fold-title{font-size:17px}
  .fact.lead b{font-size:19px}
  .nums,.nums.four{--n:2}
  /* three figures across a phone cut the money: two, and the third takes the
     whole row rather than sitting in a half-empty one */
  .nums.three{--n:2}
  .nums.three>.num-item:last-child{grid-column:1/-1}
  .nums.three>.num-item:last-child .n-val{font-size:min(32px,7.5cqi)}
  .nums,.nums.three,.nums.four{margin-bottom:20px}
  .cal .day{min-height:56px;padding:6px 4px;align-items:center;gap:4px}
  .cal .day .marks{display:flex;gap:3px;flex-wrap:wrap;justify-content:center}
  .cal .mark{display:block;width:7px;height:7px;padding:0;border-radius:50%;font-size:0;background:var(--mc,var(--mist))}
  .cal .mark.job.finished{background:transparent;box-shadow:inset 0 0 0 1.5px var(--mist)}
  .cal .mark::before{display:none}
  .cal .more{display:none}
  .leads .toolbar{flex-direction:column;align-items:stretch;gap:10px}
  .leads .chips{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;min-width:0;width:calc(100% + 28px);max-width:calc(100% + 28px);margin:0 -14px;padding:2px 14px 6px;mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent);-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent)}
  .leads .chips::-webkit-scrollbar{display:none}
  .leads .chips .chip{flex:none}
  .leads .toolbar .sort{justify-content:space-between}
  .leads .toolbar .sort .select{flex:1}
  .contractors .toolbar{flex-direction:column;align-items:stretch;gap:10px}
  .contractors .toolbar .sort{flex-wrap:wrap}
  .contractors .toolbar .sort .select,.contractors .toolbar .sort .input{flex:1 1 140px;width:auto;min-width:0}
  .contractors .toolbar .sort .btn{flex:1 1 100%}
  .cgrid{grid-template-columns:1fr}
  .goal-bar{margin-bottom:32px}
  .two{grid-template-columns:1fr}
  .person-row{grid-template-columns:minmax(0,1fr);gap:10px}
  .person-row .row-actions{justify-content:flex-start}
  .person-row .row-actions .btn{min-height:44px;flex:1 1 auto;justify-content:center}
  /* the more button stays a square beside full width buttons (2026-10-09) */
  .row-actions .btn.more-btn{flex:none;width:46px;min-width:46px;padding:0;justify-content:center}
  .lead-row .row-actions:has(.more-btn){grid-template-columns:repeat(auto-fit,minmax(104px,1fr)) 46px}
  .lead-row .row-actions .btn.more-btn{grid-column:-2/-1;grid-row:1;width:46px;height:100%}
  .person .who b{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px}
  .step-edit{grid-template-columns:minmax(0,1fr)}
  .step-edit .quick{display:flex;justify-content:flex-end;gap:6px}
  .lp-body{padding-left:16px;padding-right:16px}
  .field .lbl-spacer{display:none}
  .lp-section .form-actions,.lp-section .visit-actions,.lp-section .row-actions,.lp-foot{display:flex;flex-direction:column;align-items:stretch;gap:10px;justify-content:flex-start !important;margin-top:4px}
  .lp-section .form-actions .btn,.lp-section .visit-actions .btn,.lp-section .row-actions .btn,.lp-foot .btn{width:100%;justify-content:center;min-height:46px;font-size:15px}
  .lp-section .form-actions .form-note{order:-1;width:100%;margin:0 0 2px}
  .lp-section .link-btn{align-self:flex-start;min-height:44px;display:inline-flex;align-items:center}
  .sheet-actions,.sheet-body .form-actions{display:flex;flex-direction:column-reverse;align-items:stretch;gap:10px}
  .sheet-actions .btn,.sheet-body .form-actions .btn{width:100%;justify-content:center;min-height:46px}
  .qb-actions{display:flex;flex-direction:column;align-items:stretch}
  .qb-actions .btn,.qb-made{width:100%;justify-content:center}
  .caption-box{flex-direction:column;align-items:stretch}
  .caption-box .btn{width:100%}
  .lightbox figcaption{padding:0 64px}
  .cal-tools .gcal-note{flex-basis:100%;margin:0}
  #rpPms .table td:nth-child(2),#rpPms .table th:nth-child(2),#rpPms .table td:nth-child(5),#rpPms .table th:nth-child(5){display:none}
  #rpContractors .table td:nth-child(2),#rpContractors .table th:nth-child(2),#rpContractors .table td:nth-child(3),#rpContractors .table th:nth-child(3),#rpContractors .table td:nth-child(6),#rpContractors .table th:nth-child(6){display:none}
}
@media(max-width:600px){.bl-quiet{padding:4px 12px 14px}}
@media(max-width:400px){
  .kpis,.reports .kpis,.grid-3,.grid-2{grid-template-columns:minmax(0,1fr)}
  .kpi{border-left:0;border-top:1px solid var(--line)}
  .kpi:first-child{border-top:0}
  .team-strip,.pay-strip{grid-template-columns:minmax(0,1fr)}
  .k-val{font-size:min(24px,15cqi)}
  .pgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:360px){
  .panel:not(.fold):not(.group-open){padding:16px 14px}
  .fold-head,.og-head{padding:14px}
  .fold-body>*{padding-left:14px;padding-right:14px}
  .fold-body>.lead-row{padding-left:14px;padding-right:14px}
  .fold-body>.tpl-card .tpl-head,.fold-body>.tpl-card .tpl-body{padding-left:14px;padding-right:14px}
  .fold-body>.rt-grid,.fold-body>.rt-dow{padding-left:2px;padding-right:2px}
  /* named with its screen: the panel padding rule above outranks a bare
     .panel.tight, and it had put 14px back each side, 36.6px days at 320 */
  .calendar>.panel.tight{padding-left:0;padding-right:0}
  .panel.tight>*:not(.cal){padding-left:14px;padding-right:14px}
  .cal,.rt-grid{gap:1px}
  .cal .day{padding:6px 2px;min-width:0}
  .rt-day{min-width:0}
  .card-fields{grid-template-columns:1fr}
  /* 4px, not 9: with the 44px touch buttons the Open arrow wrapped onto a line of its own at 320 */
  .lead-card .card-line{flex-wrap:wrap;row-gap:12px;column-gap:4px}
  .n-val{font-size:min(26px,15cqi)}
}
/* Reports' QuickBooks tables sit in half a panel: 18px a side was a third of
   a 299px cell at 1024, and "Best customers" scrolled sideways there and at 320 */
#rpQb .bl-table th,#rpQb .bl-table td{padding-left:10px;padding-right:10px}
/* Reports' QuickBooks panels are one grid: a short list does not stretch to the chart beside it */
#rpQb .grid-2{align-items:start}
@media(max-width:400px){ #rpQb .bl-table th,#rpQb .bl-table td{padding-left:6px;padding-right:6px} }
/* the report tables keep the name column and shrink the numbers */
#rpPms .table,#rpContractors .table{font-size:13.5px}
#rpPms .table th,#rpContractors .table th{padding:4px 8px 10px;white-space:nowrap}
#rpPms .table td,#rpContractors .table td{padding:11px 8px;white-space:nowrap;width:1%}
#rpPms .table td:first-child,#rpContractors .table td:first-child,#rpPms .table th:first-child,#rpContractors .table th:first-child{white-space:normal;width:auto;min-width:150px;padding-left:4px;font-weight:600}
@media(max-width:680px){
  #rpPms .table td,#rpContractors .table td,#rpPms .table th,#rpContractors .table th{padding-left:6px;padding-right:6px}
  #rpPms .table td:first-child,#rpContractors .table td:first-child,#rpPms .table th:first-child,#rpContractors .table th:first-child{min-width:100px;padding-left:2px}
}
