/* SignWindowsCRM components — built ONLY on tokens.css. */

/* ---- layout shell ---- */
.layout{display:grid;grid-template-columns:var(--sidebar) 1fr;min-height:100vh}
.sidebar{background:#0e1b27;color:#c7d3de;display:flex;flex-direction:column;
  position:sticky;top:0;height:100vh;overflow-y:auto}
.sidebar .brand{display:flex;align-items:center;gap:10px;padding:14px var(--sp2);
  font-size:var(--fs-lg);font-weight:700;color:#fff;border-bottom:1px solid rgba(255,255,255,.08)}
.sidebar .brand .dot{width:22px;height:22px;border-radius:5px;background:var(--accent);
  display:inline-flex;align-items:center;justify-content:center;color:#fff;font-size:12px}
.nav-group{padding:10px var(--sp2) 4px;font-size:var(--fs-xs);text-transform:uppercase;
  letter-spacing:.08em;color:#5f7a90}
.nav a{display:flex;align-items:center;gap:9px;padding:7px var(--sp2);color:#c7d3de;
  font-size:var(--fs);border-left:3px solid transparent}
.nav a:hover{background:rgba(255,255,255,.05);text-decoration:none;color:#fff}
.nav a.active{background:rgba(1,112,185,.18);border-left-color:var(--accent);color:#fff}
.nav-badge{margin-left:auto;background:var(--accent);color:#fff;font-size:11px;font-weight:700;
  border-radius:999px;padding:0 7px;line-height:1.6;font-variant-numeric:tabular-nums}

.main{display:flex;flex-direction:column;min-width:0}
/* The inset padding + matching height are what keep the topbar out from under the
   notch in an installed PWA. They only resolve to non-zero with viewport-fit=cover on
   the viewport meta (templates/_pwa_head.html) — the two must ship together. */
.topbar{height:calc(var(--topbar) + env(safe-area-inset-top));
  padding-top:env(safe-area-inset-top);
  background:var(--panel);border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:var(--sp2);
  padding-left:var(--sp3);padding-right:var(--sp3);position:sticky;top:0;z-index:20}
.topbar .search{flex:1;max-width:420px}
.topbar .search input{width:100%;padding:7px 11px;border:1px solid var(--line);
  border-radius:var(--r);font-size:var(--fs);background:var(--panel-alt)}
.topbar .spacer{flex:1}
.topbar .user{display:flex;align-items:center;gap:8px;color:var(--ink-soft);font-size:var(--fs-sm)}
.topbar .user .logout-form{display:inline;margin:0}
.linkbtn{background:none;border:0;padding:0;margin:0;font:inherit;color:var(--accent);
  cursor:pointer;text-decoration:underline}
.content{padding:var(--sp3);width:100%}

/* ---- panels ---- */
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow);padding:var(--sp2) var(--sp3);margin-bottom:var(--sp3)}
.panel h2{display:flex;align-items:center;gap:8px;font-weight:700;
  margin:0 0 var(--sp2);padding-bottom:var(--sp);border-bottom:1px solid var(--line-soft)}
.grid{display:grid;gap:var(--sp3)}
.grid.cols-2{grid-template-columns:1fr 1fr}
.grid.cols-3{grid-template-columns:repeat(3,1fr)}
.grid.cols-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:1000px){.grid.cols-3,.grid.cols-4{grid-template-columns:1fr 1fr}}

/* ---- toolbar / breadcrumbs ---- */
.toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--sp2)}
.toolbar .actions{display:flex;gap:8px}
.breadcrumbs{font-size:var(--fs-sm);color:var(--ink-faint);margin-bottom:6px}
.breadcrumbs a{color:var(--ink-soft)}

/* ---- data tables (dense, zebra) ---- */
.data-table{width:100%;border-collapse:collapse;font-size:var(--fs)}
.data-table th{text-align:left;padding:8px 10px;font-size:var(--fs-xs);text-transform:uppercase;
  letter-spacing:.05em;color:var(--ink-faint);border-bottom:1px solid var(--line);
  background:var(--panel-alt);position:sticky;top:0;cursor:pointer;white-space:nowrap}
.data-table td{padding:8px 10px;border-bottom:1px solid var(--line-soft);vertical-align:middle}
.data-table tbody tr:nth-child(even){background:var(--panel-alt)}
.data-table tbody tr:hover{background:var(--accent-tint)}
.data-table td.num,.data-table th.num{text-align:right;font-variant-numeric:tabular-nums}

/* ---- pills ---- */
.pill{display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border-radius:var(--r-pill);
  font-size:var(--fs-xs);font-weight:600;background:var(--line-soft);color:var(--ink-soft);white-space:nowrap}
.pill::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.7}
.pill--ok{background:var(--ok-tint);color:var(--ok)}
.pill--warn{background:var(--warn-tint);color:var(--warn)}
.pill--bad{background:var(--bad-tint);color:var(--bad)}
.pill--info{background:var(--info-tint);color:var(--info)}

/* ---- buttons ---- */
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 13px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--panel);color:var(--ink);font-size:var(--fs);
  font-weight:550;cursor:pointer;font-family:var(--font)}
.btn:hover{background:var(--panel-alt);text-decoration:none}
.btn--primary{background:var(--accent);border-color:var(--accent);color:#fff}
.btn--primary:hover{background:var(--accent-dark)}
.btn--sm{padding:4px 9px;font-size:var(--fs-sm)}
.btn--ghost{border-color:transparent;background:transparent;color:var(--accent)}
.btn--warn{background:var(--warn-tint);border-color:var(--warn);color:var(--warn)}
.btn--warn:hover{background:var(--warn);color:#fff}

/* ---- KPI cards ---- */
.kpi{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:var(--sp2) var(--sp3);box-shadow:var(--shadow)}
.kpi .label{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint)}
.kpi .value{font-size:var(--fs-xxl);font-weight:700;letter-spacing:-.02em;margin-top:4px;
  font-variant-numeric:tabular-nums}
.kpi .sub{font-size:var(--fs-sm);color:var(--ink-soft);margin-top:2px}

/* ---- forms ---- */
label{display:block;font-size:var(--fs-sm);color:var(--ink-soft);margin:0 0 4px}
input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{
  width:100%;padding:7px 10px;border:1px solid var(--line);
  border-radius:var(--r);font-size:var(--fs);font-family:var(--font);background:var(--panel)}
input[type=checkbox],input[type=radio]{width:auto;margin:0}
input:focus,select:focus,textarea:focus{outline:2px solid var(--accent-tint);border-color:var(--accent)}
.field{margin-bottom:var(--sp2)}
.row{display:flex;gap:var(--sp2)}.row>*{flex:1}

/* ---- shared section / help / callout / chip primitives (one source of truth) ---- */
.subsec{border-top:1px solid var(--line-soft);margin-top:var(--sp2);padding-top:var(--sp2)}
.subsec:first-child{border-top:none;margin-top:0;padding-top:0}
.subsec__head{font-size:var(--h4);font-weight:600;text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-faint);margin:0 0 var(--sp)}
.help{font-size:var(--fs-sm);color:var(--ink-soft);margin:0 0 var(--sp)}
.help--faint{font-size:var(--fs-xs);color:var(--ink-faint)}
.help--alert{color:var(--bad)}
.req{color:var(--bad);font-weight:700}
.sub{font-weight:400;color:var(--ink-faint);font-size:var(--fs-sm)}
.callout{border-radius:var(--r);padding:var(--sp) var(--sp2);font-size:var(--fs-sm);margin:var(--sp) 0;
  border:1px solid var(--line);background:var(--panel-alt);color:var(--ink-soft)}
.callout--ok{background:var(--ok-tint);border-color:var(--ok);color:var(--ok)}
.callout--warn{background:var(--warn-tint);border-color:var(--warn);color:var(--warn)}
.callout--bad{background:var(--bad-tint);border-color:var(--bad);color:var(--bad)}
.btn--cta{width:100%;padding:var(--sp2);font-size:var(--fs-lg);font-weight:700;margin-top:var(--sp)}
.chip-name{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-sm);color:var(--ink-soft)}
.chip-name .av{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;
  border-radius:50%;background:var(--accent-tint);color:var(--accent-dark);font-size:10px;font-weight:700;text-transform:uppercase}
.pill--mine{background:var(--accent);color:#fff}
.pill--mine::before{background:#fff}

/* ---- AI draft preview ---- */
.preview{background:var(--accent-tint);border:1px solid #c5dcec;border-radius:var(--r);
  padding:var(--sp2);position:relative;white-space:pre-wrap;font-size:var(--fs);margin-top:var(--sp)}
.preview .copy{position:absolute;top:8px;right:8px}
.ai-badge{font-size:var(--fs-xs);padding:1px 7px;border-radius:var(--r-pill);
  background:var(--accent-tint);color:var(--accent);font-weight:600}
.ai-badge.off{background:var(--warn-tint);color:var(--warn)}

/* ---- misc ---- */
.empty{text-align:center;color:var(--ink-faint);padding:var(--sp3);font-size:var(--fs)}
.flash{background:var(--warn-tint);color:var(--warn);padding:9px var(--sp2);border-radius:var(--r);
  margin-bottom:var(--sp2);border:1px solid #f0d9a8}
.modal-bg{position:fixed;inset:0;background:rgba(14,27,39,.4);display:flex;align-items:center;
  justify-content:center;z-index:50}
.modal{background:var(--panel);border-radius:var(--r-lg);box-shadow:var(--shadow-lg);
  padding:var(--sp3);max-width:560px;width:90%}
kbd{font-family:var(--mono);font-size:var(--fs-xs);background:var(--line-soft);
  border:1px solid var(--line);border-radius:4px;padding:1px 5px}

/* ---- mobile nav toggle (hidden on desktop) ---- */
.nav-toggle{display:none;background:transparent;border:1px solid var(--line);
  border-radius:var(--r);font-size:18px;line-height:1;padding:5px 10px;cursor:pointer;color:var(--ink)}
.nav-scrim{display:none}

/* ---- responsive ---- */
/* Hidden until the phone breakpoint below — a desktop browser keeps the plain page. */
.tabbar{display:none}
@media(max-width:860px){
  .layout{grid-template-columns:1fr}
  .sidebar{position:fixed;left:0;top:0;height:100vh;width:var(--sidebar);z-index:60;
    transform:translateX(-100%);transition:transform .2s ease}
  body.nav-open .sidebar{transform:translateX(0)}
  body.nav-open .nav-scrim{display:block;position:fixed;inset:0;z-index:55;
    background:rgba(14,27,39,.4)}
  .nav-toggle{display:inline-flex;align-items:center;justify-content:center}
  /* Deliberately here and not on the base .content rule: that rule uses the `padding`
     SHORTHAND at identical specificity, so anything set further up is wiped at exactly
     the widths that have a notch. Landscape on a notched phone puts the content under
     the sensor housing without the left/right insets. */
  .content{padding:var(--sp2);
    padding-left:calc(var(--sp2) + env(safe-area-inset-left));
    padding-right:calc(var(--sp2) + env(safe-area-inset-right));
    padding-bottom:calc(var(--sp2) + env(safe-area-inset-bottom))}
  /* toolbars carry actions + a search box on the board — let them wrap on a
     phone instead of overflowing off-screen */
  .toolbar{flex-wrap:wrap;gap:var(--sp);align-items:flex-start}
  .toolbar .actions{flex-wrap:wrap}
  .topbar{gap:var(--sp);
    padding-left:calc(var(--sp2) + env(safe-area-inset-left));
    padding-right:calc(var(--sp2) + env(safe-area-inset-right))}
  .grid.cols-4,.grid.cols-3,.grid.cols-2{grid-template-columns:1fr 1fr}
  /* let wide data tables scroll horizontally instead of squashing */
  .panel{overflow-x:auto}

  /* ---- fitters PWA bottom tab bar (installer role, phone only) ---------------
     Revealed at the SAME breakpoint the sidebar disappears at, so an installer on a
     desktop browser keeps the plain page. z-index 40: above the sticky topbar (20),
     below the nav scrim/sidebar (55/60) and the search dropdown (50) — and far below
     the job photo lightboxes (9998-10001), which are full-screen and must never have
     a nav bar floating across them. */
  .tabbar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:40;
    background:var(--panel);border-top:1px solid var(--line);
    padding-bottom:env(safe-area-inset-bottom);
    padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}
  .tabbar .tab{flex:1 1 0;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:2px;min-height:56px;text-decoration:none;
    color:var(--ink-soft);font-size:var(--fs-xs);font-weight:600}
  .tabbar .tab.is-on{color:var(--accent)}
  .tabbar .tab__ic{font-size:18px;line-height:1}
  .tabbar .tab:active{background:var(--bg)}
  /* The bar is fixed, so without this it sits on top of the last thing on the page —
     on my-work that is the last job card's "I'm on this job" button. Specificity
     (0,3,1) beats .content (0,1,1), so it survives the `padding` SHORTHAND
     re-declaration above regardless of source order. */
  .layout.has-tabs .content{
    padding-bottom:calc(var(--sp2) + 56px + env(safe-area-inset-bottom))}
}
@media(max-width:560px){
  /* ---- phone-first for FIELD ROLES ONLY -------------------------------------
     16px is the threshold below which iOS Safari zooms the page when an input takes
     focus. The base font is 13px, so every text and number field on a job jerked the
     whole screen sideways on tap — on a fitter's phone, all day.

     Scoped to .layout.no-side (base.html emits it for exactly the field roles) and
     NOT applied globally: a global rule would reflow the warehouse board, dispatch,
     sales, survey, leads, inbox and the timesheet on every iPad and Android tablet in
     the business, and there is no visual regression test in this repo to catch it.

     Specificity (0,5,1) — two classes plus three attribute selectors — which beats the
     base `input:not(...)` rule at (0,3,1).

     Known gap, accepted: 560px means a phone in LANDSCAPE (844px wide) still zooms.
     That matches the breakpoint the rest of the app already uses, rather than a
     pointer:coarse query that would also restyle the office iPad. (The rules in
     sales/detail.html and survey/detail.html that look like they do this job are
     inside a landscape-only media query and never match a portrait phone at all.) */
  .layout.no-side input:not([type=checkbox]):not([type=radio]):not([type=range]),
  .layout.no-side select,
  .layout.no-side textarea{font-size:16px;min-height:44px}
  .layout.no-side .btn{min-height:44px}
  .layout.no-side summary{min-height:44px}

  .grid.cols-4,.grid.cols-3,.grid.cols-2{grid-template-columns:1fr}
  .topbar .search{max-width:none}
  /* keep the topbar from overflowing on a phone: drop the AI badge, let the
     name truncate, and keep the ❔ Guide button from shrinking */
  .topbar .ai-badge{display:none}
  .topbar #ob-open-btn{flex:0 0 auto}
  .topbar .user{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
}

/* ---- customer autocomplete ---- */
.ac-menu{position:relative;z-index:30;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow-lg);margin-top:2px;max-height:260px;overflow-y:auto}
.ac-item{display:block;width:100%;text-align:left;border:none;background:transparent;
  padding:7px 10px;cursor:pointer;font-size:var(--fs);border-bottom:1px solid var(--line-soft)}
.ac-item:last-child{border-bottom:none}
.ac-item:hover{background:var(--accent-tint)}
.ac-item span{color:var(--ink-faint);font-size:var(--fs-sm)}

/* ---- a11y ---- */
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}
.sidebar .nav a:focus-visible{outline-offset:-2px}
a.skip-link{position:absolute;left:-999px;top:8px;z-index:100;background:var(--accent);
  color:#fff;padding:8px 14px;border-radius:var(--r)}
a.skip-link:focus{left:8px}

@media print{
  .sidebar,.topbar,.toolbar .actions,.btn{display:none!important}
  .layout{grid-template-columns:1fr}.content{padding:0}
  .panel{box-shadow:none;border:none}
}

/* ---- live filter bar (shared via _macros.filter_bar) ---- */
.filter-bar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0 0 14px}
.filter-bar input[type=search],.filter-bar input[type=date],.filter-bar select{
  flex:1 1 160px;width:auto;min-width:138px;max-width:280px;
  padding:7px 10px;border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  font-size:var(--fs);color:var(--ink);min-height:36px}
.filter-bar input[type=search]{flex:2 1 200px;min-width:170px;max-width:none}
.filter-bar .filter-clear{flex:0 0 auto}
.filter-bar input:focus,.filter-bar select:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(1,112,185,.15)}
.filter-bar .filter-clear{font-size:var(--fs-sm);color:var(--ink-soft);text-decoration:none;margin-left:2px}
.filter-bar .filter-clear:hover{color:var(--accent);text-decoration:underline}
.filter-bar.htmx-request{opacity:.6}

/* ---- admin onboarding guide popup ---- */
.ob-bg{padding:var(--sp2)}
.ob-modal{max-width:520px;width:100%;padding:0;overflow:hidden;position:relative}
.ob-x{position:absolute;top:6px;right:6px;background:transparent;border:none;font-size:16px;
  line-height:1;color:var(--ink-faint);cursor:pointer;border-radius:var(--r);
  min-width:44px;min-height:44px;display:inline-flex;align-items:center;justify-content:center}
.ob-x:hover{background:var(--line-soft);color:var(--ink)}
.ob-head{display:flex;gap:14px;align-items:flex-start;padding:var(--sp3) var(--sp3) var(--sp);
  border-bottom:1px solid var(--line-soft)}
.ob-icon{font-size:30px;line-height:1;flex:0 0 auto}
.ob-kicker{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);font-weight:600}
.ob-title{font-size:var(--fs-xl);margin:2px 0 0;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ob-new{font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.04em;
  background:var(--accent);color:#fff;border-radius:var(--r-pill);padding:1px 8px}
.ob-body{margin:0;padding:var(--sp2) var(--sp3) var(--sp);list-style:none;display:flex;
  flex-direction:column;gap:10px}
.ob-body li{position:relative;padding-left:24px;font-size:var(--fs-lg);line-height:1.5;color:var(--ink)}
.ob-body li::before{content:"";position:absolute;left:6px;top:9px;width:7px;height:7px;
  border-radius:50%;background:var(--accent)}
.ob-body strong{font-weight:650}
.ob-dots{display:flex;gap:6px;justify-content:center;padding:4px 0 0}
.ob-dot{width:8px;height:8px;border-radius:50%;border:none;background:var(--line);cursor:pointer;padding:0}
.ob-dot.on{background:var(--accent);width:20px;border-radius:var(--r-pill)}
.ob-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--sp2);
  padding:var(--sp2) var(--sp3) var(--sp3)}
.ob-nav{display:flex;gap:8px}
@media(max-width:560px){
  .ob-modal{max-width:none}
  .ob-head{padding:var(--sp2) var(--sp2) var(--sp)}
  .ob-body{padding:var(--sp2)}
  .ob-foot{padding:var(--sp) var(--sp2) var(--sp2);flex-wrap:wrap}
  .ob-body li{font-size:var(--fs-lg)}
  .ob-nav{flex:1;justify-content:flex-end}
}

/* ---- live global-search dropdown (topbar) ---- */
.search{position:relative}
.search-dropdown{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:50;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-lg);max-height:70vh;overflow:auto;display:none}
.search-dropdown:not(:empty){display:block}
.search-dropdown .sd-group{padding:6px 0;border-bottom:1px solid var(--line-soft)}
.search-dropdown .sd-group:last-child{border-bottom:none}
.search-dropdown .sd-head{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-faint);padding:6px 14px 2px}
.search-dropdown a{display:flex;justify-content:space-between;gap:10px;padding:7px 14px;
  color:var(--ink);text-decoration:none;font-size:var(--fs)}
.search-dropdown a:hover,.search-dropdown a.is-active{background:var(--accent-tint)}
.search-dropdown .sd-meta{color:var(--ink-faint);font-size:var(--fs-sm)}
.search-dropdown .sd-empty{padding:12px 14px;color:var(--ink-faint);font-size:var(--fs-sm)}

/* Field-role tab strip in the topbar. Only the sales role renders one: it has no
   sidebar and no hamburger, so this is its only route between the board and the
   call sheet. */
.field-tabs{display:flex;gap:4px;margin-left:12px}
.field-tabs a{font-size:var(--fs-sm);font-weight:600;color:var(--ink-soft);
  text-decoration:none;padding:6px 11px;border-radius:var(--r-pill);white-space:nowrap}
.field-tabs a:hover{background:var(--panel-alt);color:var(--ink)}
.field-tabs a.on{background:var(--accent-tint);color:var(--accent-dark);font-weight:700}
/* On a phone the tabs, the brand and the user block fight over one line and
   Logout gets clipped. Scoped with :has() so only a topbar carrying tabs is
   affected — every other role's header is untouched. */
@media (max-width:560px){
  .field-tabs{margin-left:8px;gap:2px}
  .field-tabs a{padding:6px 9px;font-size:var(--fs-xs)}
  .topbar:has(.field-tabs) .brand span.dot{margin-right:0}
  .topbar:has(.field-tabs) .brand{font-size:0}
  .topbar:has(.field-tabs) .brand span.dot{font-size:var(--fs-md)}
  .topbar:has(.field-tabs) .user{font-size:0}
  .topbar:has(.field-tabs) .user .linkbtn{font-size:var(--fs-sm)}
}
