/*
 * SolarExpert.
 *
 * Mobile first, and not as a slogan: the survey half of this product is used
 * standing on a roof in the sun, on a phone, one-handed. So targets are large,
 * the palette holds up at full brightness outdoors, and every layout starts as
 * one column and earns its second at 900px.
 */

:root {
  --ink:        #10241b;
  --ink-soft:   #4a5f55;
  --ink-faint:  #7b8c84;

  --green:      #0d3b26;
  --green-mid:  #1e6f3c;
  --green-lite: #e8f3ec;
  --sun:        #e8a33d;
  --sun-lite:   #fdf3e2;

  --red:        #b3261e;
  --red-lite:   #fdecea;

  --page:       #f6f8f7;
  --card:       #ffffff;
  --line:       #dde5e1;
  --line-soft:  #eef2f0;

  --radius:     10px;
  --radius-lg:  14px;
  --shadow:     0 1px 2px rgba(16, 36, 27, .06), 0 4px 16px rgba(16, 36, 27, .05);

  --header-h:   56px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--page);
  color: var(--ink);
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { margin: 0 0 .5em; line-height: 1.25; font-weight: 650; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.15rem; }
h3 { font-size: 1rem; }
p  { margin: 0 0 1em; }
a  { color: var(--green-mid); }

/* --- layout ------------------------------------------------------------- */

.shell { min-height: 100vh; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 40;
  height: var(--header-h);
  display: flex; align-items: center; gap: 12px;
  padding: 0 14px;
  background: var(--green);
  color: #fff;
  padding-top: env(safe-area-inset-top);
  height: calc(var(--header-h) + env(safe-area-inset-top));
}
.topbar .brand {
  font-weight: 700; letter-spacing: -.01em; font-size: 1.05rem;
  display: flex; align-items: center;
}
.topbar .brand span { color: var(--sun); }
.topbar .spacer { flex: 1; }

.credits-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(255, 255, 255, .13);
  border: 1px solid rgba(255, 255, 255, .18);
  color: #fff;
  padding: 5px 11px; border-radius: 999px;
  font-size: .82rem; font-weight: 600;
  cursor: pointer;
}
.credits-pill.dry { background: var(--sun); border-color: var(--sun); color: #3a2500; }
.credits-pill b { font-variant-numeric: tabular-nums; }

.nav {
  display: flex; gap: 2px; overflow-x: auto;
  background: var(--card); border-bottom: 1px solid var(--line);
  padding: 0 8px;
  position: sticky; top: calc(var(--header-h) + env(safe-area-inset-top)); z-index: 30;
  scrollbar-width: none;
}
.nav::-webkit-scrollbar { display: none; }
.nav button {
  flex: 0 0 auto;
  background: none; border: none; border-bottom: 2px solid transparent;
  padding: 13px 14px; font: inherit; font-weight: 550; color: var(--ink-soft);
  cursor: pointer; white-space: nowrap;
}
.nav button.on { color: var(--green); border-bottom-color: var(--green-mid); }

main { flex: 1; padding: 18px 14px 64px; max-width: 1040px; width: 100%; margin: 0 auto; }

@media (min-width: 900px) {
  main { padding: 26px 24px 80px; }
  .topbar { padding: 0 24px; }
  .nav { padding: 0 16px; }
}

/* --- cards -------------------------------------------------------------- */

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 18px;
  margin: 0 0 16px;
}
.card > h2:first-child, .card > h3:first-child { margin-top: 0; }
.card-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.card-head h2, .card-head h3 { margin: 0; flex: 1; }

.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); font-size: .88rem; }
.tabular { font-variant-numeric: tabular-nums; }

/* --- buttons ------------------------------------------------------------ */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 42px; padding: 0 16px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); color: var(--ink);
  font: inherit; font-weight: 600; cursor: pointer;
  text-decoration: none;
}
.btn:hover { border-color: var(--ink-faint); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.primary { background: var(--green-mid); border-color: var(--green-mid); color: #fff; }
.btn.primary:hover { background: #185c32; }
.btn.sun { background: var(--sun); border-color: var(--sun); color: #3a2500; }
.btn.sun:hover { filter: brightness(.96); }
.btn.danger { color: var(--red); border-color: #f0c9c6; }
.btn.ghost { background: none; border-color: transparent; color: var(--green-mid); }
.btn.small { min-height: 34px; padding: 0 11px; font-size: .87rem; }
.btn.block { width: 100%; }
.btn-row { display: flex; flex-wrap: wrap; gap: 9px; }

/* --- forms -------------------------------------------------------------- */

.field { margin: 0 0 14px; }
.field label {
  display: block; font-size: .82rem; font-weight: 600;
  color: var(--ink-soft); margin-bottom: 5px;
}
.field input, .field select, .field textarea {
  width: 100%; min-height: 42px; padding: 9px 11px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; color: var(--ink); font: inherit;
}
.field textarea { min-height: 84px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--green-mid);
  box-shadow: 0 0 0 3px rgba(30, 111, 60, .13);
}
.field .hint { font-size: .8rem; color: var(--ink-faint); margin-top: 5px; }
.field-row { display: grid; gap: 0 14px; }
@media (min-width: 640px) { .field-row.two { grid-template-columns: 1fr 1fr; } }

/* --- messages ----------------------------------------------------------- */

.note {
  border-radius: var(--radius); padding: 12px 14px; margin: 0 0 16px;
  border: 1px solid var(--line); background: var(--line-soft); font-size: .92rem;
}
.note.bad   { background: var(--red-lite);  border-color: #f2cdc9; color: #7c1b15; }
.note.warn  { background: var(--sun-lite);  border-color: #f2ddb5; color: #6b4a10; }
.note.good  { background: var(--green-lite); border-color: #c9e2d3; color: #0f4a2c; }
.note strong { font-weight: 650; }

.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  background: var(--ink); color: #fff; padding: 11px 18px;
  border-radius: 999px; font-size: .9rem; z-index: 200;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .25);
  max-width: calc(100vw - 32px);
}
.toast.bad { background: var(--red); }

/* --- tables ------------------------------------------------------------- */

.table-wrap { overflow-x: auto; margin: 0 -18px; padding: 0 18px; }
table { width: 100%; border-collapse: collapse; font-size: .92rem; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line-soft); }
th { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); font-weight: 650; }
tbody tr:last-child td { border-bottom: none; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* On a phone every row becomes its own block, captioned from the header. */
@media (max-width: 700px) {
  table.cards thead { display: none; }
  table.cards tr {
    display: block; border: 1px solid var(--line); border-radius: var(--radius);
    padding: 10px 12px; margin-bottom: 9px;
  }
  table.cards td {
    display: flex; justify-content: space-between; gap: 14px;
    border: none; padding: 4px 0; text-align: right;
  }
  table.cards td::before {
    content: attr(data-label);
    font-size: .78rem; text-transform: uppercase; letter-spacing: .04em;
    color: var(--ink-faint); font-weight: 650; text-align: left;
  }
}

/* --- site list ---------------------------------------------------------- */

.site-list { display: grid; gap: 11px; }
@media (min-width: 760px) { .site-list { grid-template-columns: 1fr 1fr; } }

.site {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 15px; cursor: pointer;
  display: flex; gap: 13px; align-items: flex-start;
  box-shadow: var(--shadow);
}
.site:hover { border-color: var(--green-mid); }
.site .body { flex: 1; min-width: 0; }
.site h3 { margin: 0 0 3px; font-size: 1rem; }
.site .addr {
  color: var(--ink-soft); font-size: .87rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.site .meta { margin-top: 7px; font-size: .8rem; color: var(--ink-faint); }

.lock {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 10px;
  display: grid; place-items: center; font-size: 1.05rem;
}
.lock.locked   { background: var(--sun-lite);  color: #a06a08; }
.lock.unlocked { background: var(--green-lite); color: var(--green-mid); }

.tag {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-size: .74rem; font-weight: 650; letter-spacing: .02em;
}
.tag.locked   { background: var(--sun-lite);   color: #8a5a06; }
.tag.unlocked { background: var(--green-lite); color: var(--green-mid); }
.tag.grey     { background: var(--line-soft);  color: var(--ink-soft); }

/* --- the paywall -------------------------------------------------------- */

/* The one screen the whole product turns on. It has to read as a price, not
   as an error — nothing has gone wrong, the customer simply has not bought
   this location yet. */
.paywall {
  border: 1px solid #f0dcb8; background: linear-gradient(180deg, #fffaf1, #fdf3e2);
  border-radius: var(--radius-lg); padding: 22px; text-align: center;
}
.paywall .icon { font-size: 2rem; }
.paywall h2 { margin: 10px 0 6px; }
.paywall p { color: #6b4a10; max-width: 42ch; margin: 0 auto 16px; }
.paywall .cost { font-size: 1.05rem; font-weight: 700; color: #8a5a06; margin-bottom: 14px; }

/* --- ledger ------------------------------------------------------------- */

.delta { font-weight: 650; font-variant-numeric: tabular-nums; }
.delta.plus  { color: var(--green-mid); }
.delta.minus { color: var(--ink-soft); }

/* --- modal -------------------------------------------------------------- */

.backdrop {
  position: fixed; inset: 0; background: rgba(16, 36, 27, .45);
  display: flex; align-items: flex-end; justify-content: center; z-index: 100;
  padding: 0;
}
@media (min-width: 640px) { .backdrop { align-items: center; padding: 24px; } }

.modal {
  background: var(--card); width: 100%; max-width: 480px;
  border-radius: 16px 16px 0 0; padding: 20px;
  max-height: 92vh; overflow-y: auto;
  padding-bottom: calc(20px + env(safe-area-inset-bottom));
}
@media (min-width: 640px) { .modal { border-radius: var(--radius-lg); padding-bottom: 20px; } }
.modal h2 { margin-top: 0; }

/* --- sign in ------------------------------------------------------------ */

.gate { min-height: 100vh; display: grid; place-items: center; padding: 22px; }
.gate-card { width: 100%; max-width: 400px; }
.gate-brand {
  text-align: center; margin-bottom: 22px;
  font-size: 1.6rem; font-weight: 750; color: var(--green); letter-spacing: -.02em;
}
.gate-brand span { color: var(--sun); }
.gate-tag { text-align: center; color: var(--ink-soft); margin: -14px 0 24px; font-size: .93rem; }
.switch { text-align: center; margin-top: 16px; font-size: .9rem; }

/* --- misc --------------------------------------------------------------- */

/* NOTE. Bare utility classes like this one are the whole page's namespace.
   `.empty` here once collided with a `.credits-pill.empty` modifier — same
   word, two unrelated meanings — and this padding silently won, inflating the
   header's credit pill into a circle. Modifiers get a name of their own
   (`.credits-pill.dry`); only genuinely global utilities get a bare one. This
   matters more with every module ported in from Blaise's 13,500-line
   stylesheet. */
.empty { text-align: center; padding: 46px 20px; color: var(--ink-faint); }
.empty .icon { font-size: 2.2rem; opacity: .55; }
.empty h3 { margin: 12px 0 5px; color: var(--ink-soft); }

.spinner {
  width: 22px; height: 22px; margin: 40px auto;
  border: 2.5px solid var(--line); border-top-color: var(--green-mid);
  border-radius: 50%; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/*
 * The stat tiles.
 *
 * The minimum column is 172px and the figure SHRINKS TO FIT, because these
 * hold money and money in this application runs to seven figures:
 * "₱1,316,737.63" is 13 characters and it was being clipped by the card's own
 * edge — the peso sign and the millions column disappearing under the next
 * tile, which is the one part of a total nobody can guess from the rest.
 *
 * `clamp` with a container-relative middle term is what makes it degrade
 * instead of overflowing: a four-figure number keeps the full 1.5rem, a
 * seven-figure one steps down until it fits, and nothing wraps mid-number.
 */
.stat-grid { display: grid; gap: 11px; grid-template-columns: repeat(auto-fit, minmax(172px, 1fr)); }
.stat {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px; min-width: 0; overflow: hidden;
  /* Named so the figure inside can size itself against THIS tile rather than
     the viewport — two tiles of different widths on the same row each get the
     size that fits them. */
  container-type: inline-size;
}
.stat .n {
  font-size: clamp(1.02rem, 7.4cqw, 1.5rem);
  font-weight: 700; font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* The last resort, for a viewport narrow enough that even the floor of the
     clamp does not fit: shrink rather than clip. */
  overflow: hidden; text-overflow: ellipsis;
}
.stat .k { font-size: .8rem; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .04em; }


/* ===========================================================================
   The Solar Survey
   ===========================================================================
   The rules below are lifted from BLAISE 1.0's stylesheet — the 357 that the
   ported form, map and list actually use, out of its 3,345. They are a COPY,
   not a rewrite, for the same reason the modules they style are: a fix over
   there can be brought across by re-running the extraction, and a reviewer can
   diff the two.

   Blaise names its palette differently, so rather than editing 1,142 lines of
   rules, its vocabulary is aliased onto this app's below. That is also what
   makes a re-extraction cheap: nothing downstream of this block has to change.

   One consequence worth knowing: these aliases are what give the survey
   screens SolarExpert's green rather than Blaise's blue. If a survey screen
   ever looks like the wrong product, this is the block to look at. */

:root {
  --accent:        var(--green-mid);
  --accent-dark:   var(--green);
  --accent-tint:   var(--green-lite);
  --bg:            var(--page);
  --panel:         var(--card);
  --border:        var(--line);
  --border-strong: var(--ink-faint);
  --text:          var(--ink);
  --text-muted:    var(--ink-soft);
  --text-faint:    var(--ink-faint);
  --danger:        var(--red);
  --danger-tint:   var(--red-lite);
  --warn:          #8a5a06;
  --warn-tint:     var(--sun-lite);
  --success:       var(--green-mid);
  --success-tint:  var(--green-lite);
  --login-text-muted: var(--ink-soft);
}

/* The autosave pill, from ss-widgets.js. It says nothing at all while there is
   nothing to say — which is the point: a surveyor should notice it only when a
   save has failed. */
.save-status {
  position: fixed; right: 14px; bottom: 14px; z-index: 150;
  padding: 7px 13px; border-radius: 999px;
  background: var(--ink); color: #fff; font-size: .82rem; font-weight: 600;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .2);
}
.save-status.failed { background: var(--red); }

.login-card .text-muted { margin: -8px 0 4px; font-size: 12.5px; color: var(--login-text-muted); }
.login-card .field label { color: var(--login-text-muted); }
.login-card .btn-primary {
  background: linear-gradient(135deg, #38bdf8, #0ea5e9);
  border-color: #0ea5e9;
  color: #06131c;
  font-weight: 700;
}
.login-card .btn-primary:hover { background: linear-gradient(135deg, #56c8fb, #0ea5e9); border-color: #0284c7; }
.topnav nav button.active {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-weight: 600;
}
/* Same count, one level down: the tab chips inside Purchasing Department,
   Asset Management, HR and Engineering, so the nav badge can be traced to
   the exact tab that owes the work. */
.chip-badge {
  display: inline-block;
  min-width: 16px;
  padding: 0 5px;
  margin-left: 6px;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  vertical-align: middle;
}
.chip-badge[hidden] { display: none !important; }
/* On an active (accent-filled) chip a red pill fights the fill, so it flips
   to a white one that reads against it. */
.chip.active .chip-badge {
  background: #fff;
  color: var(--accent);
}
/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border-strong);
  background: var(--panel);
  color: var(--text);
  padding: 7px 13px;
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 13px;
  line-height: 1.2;
}
.btn:hover { background: #f0f2f4; }
.btn:active { background: #e6e9ec; }
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.btn-primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); }
.btn-danger {
  color: var(--danger);
  border-color: #e0b7b3;
  background: var(--danger-tint);
}
.btn-danger:hover { background: #f7dcda; }
.btn-small { padding: 4px 9px; font-size: 12px; }
.btn-text {
  border: none;
  background: transparent;
  color: var(--accent);
  padding: 4px 6px;
  cursor: pointer;
  font-size: 12.5px;
}
.btn-text:hover { text-decoration: underline; }
.btn-text.danger { color: var(--danger); }
.btn[disabled] { opacity: 0.5; cursor: default; }
/* ---------- Inputs ---------- */
.field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.field label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.form-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
.form-grid .span-2 { grid-column: span 2; }
.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.text-right { text-align: right; }
.text-muted { color: var(--text-muted); }
`, capped in
   width so a long scope stacks into a few lines rather than pushing the money
   and status columns off the side of .table-scroll. */
.scope-cell {
  white-space: normal;
  min-width: 260px;
  max-width: 420px;
  /* Freeform text, so a pasted part number or URL with no spaces in it breaks
     rather than forcing the cell past its cap. */
  overflow-wrap: anywhere;
  line-height: 1.4;
}
/* These live inside #u-pages-field, which is a .field — and `.field label` is
   an uppercase muted style meant for a field's own caption. The .perm-tree
   prefix is what outranks it; without it every page name and every seat below
   renders as a tiny grey all-caps label. */
.perm-tree .perm-group-title {
  margin: 0;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--accent);
}
/* Project Monitoring's status dropdown.

   It had no styling at all, so the browser was free to shrink it to its
   minimum content width — in an auto-layout table with eight other columns
   competing, that collapsed it to about three characters and every row read
   "Cc" instead of "Completed".

   The width is set from the LONGEST OPTION, not the selected one: a select
   shows one value at a time, and sizing it to fit "Completed" would truncate
   the moment somebody picked "Waiting for Client Schedule". min-width rather
   than width so the column can still grow with the table; the table already
   scrolls horizontally inside .table-scroll, so nothing is squeezed by it. */
.pm-status-select {
  min-width: 200px;
  width: 100%;
  font: inherit;
  font-size: 12px;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
}
/* ---------- Toolbar / filters ---------- */
.toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.toolbar input[type="text"] { width: 260px; }
.chip {
  border: 1px solid var(--border-strong);
  background: #fff;
  border-radius: 12px;
  padding: 5px 12px;
  font-size: 12px;
  cursor: pointer;
  color: var(--text-muted);
}
.chip.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
/* ---------- Tab strips ----------

   `.tab-strip` marks a .toolbar that is PURE NAVIGATION — a row of .chip
   buttons and nothing else. Filter bars keep the plain .toolbar class, because
   they must go on wrapping onto as many lines as they need.

   The distinction only matters on a phone. Three of these strips stack up on a
   page reached through a parent (HR → Asset Management → Company Vehicle
   Inspection), and wrapped at 375px they came to roughly 1,100px of chrome —
   the whole screen was navigation before a single field appeared.

   Below 760px a strip of more than three chips is replaced by a native
   <select>, generated from the chips by syncTabNav() in app.js. Three or fewer
   stays as chips — a dropdown holding two options is worse than two buttons —
   and those short strips scroll sideways rather than wrapping, with
   revealActiveTabs() keeping the selected one in view.

   Desktop is untouched by all of this: the select is display:none and the
   chips wrap exactly as they always have. */

.tab-nav-select { display: none; }
@media (max-width: 760px) {
  /* The dropdown that replaces a long strip. Deliberately a native <select>:
     it gets the platform's own picker — a wheel on iOS, a sheet on Android —
     which is a far better way through fourteen options than any list this app
     could draw, and it is reachable by a screen reader for free. */
  .tab-nav-select {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-bottom: 10px;
    padding: 10px 12px;
    /* 16px stops iOS Safari zooming the page in when the picker opens. */
    font-size: 16px;
    font-weight: 600;
    font-family: inherit;
    color: var(--text);
    background: var(--panel);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
  }

  .tab-strip.has-nav-select { display: none; }

  /* The short strips that keep their chips. */
  .tab-strip:not(.has-nav-select) {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    gap: 6px;
    margin-bottom: 10px;
    padding-bottom: 2px;
    /* The scrollbar is noise on a strip this short, and on iOS it does not
       render at all — a tab half-cut at the right edge is the affordance. */
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .tab-strip:not(.has-nav-select)::-webkit-scrollbar { display: none; }

  /* Without this a chip shrinks to fit rather than overflowing, and the row
     turns back into unreadable slivers instead of scrolling. */
  .tab-strip:not(.has-nav-select) > * { flex: 0 0 auto; }

  /* A 5px-tall tap target is a miss waiting to happen. */
  .tab-strip .chip {
    padding: 8px 14px;
    font-size: 13px;
    border-radius: 14px;
  }
}
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  min-width: 0;
}
.card h2 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-muted);
  margin: 0 0 12px;
  font-weight: 700;
}
.discount-toggle button.active { background: var(--accent); color: #fff; }
.table-scroll { overflow-x: auto; }
` and dragging the whole row off the side of
   its .table-scroll. This is the read-only counterpart of the wrapping text
   fields below — same problem, but nothing here is typed into. */
.inv-item-wrap-cell {
  white-space: normal;
  min-width: 150px;
  max-width: 280px;
}
/* max-width: 0 keeps the (wide) content panel from driving the width of the
   project table it's nested inside — without it the panel's own minimum
   width becomes the table's, pushing the Progress/Payment columns off the
   right edge of every row. The panel scrolls inside .pm-detail-scroll
   instead, same idea as .table-scroll one level up. */
.pm-detail-row > td {
  background: #fbfcfd;
  padding: 14px 16px;
  max-width: 0;
  /* white-space is inherited, so the global `th, td { white-space: nowrap }`
     would otherwise reach every paragraph and caption inside this panel and
     stop them wrapping. The panel's own table cells re-match that rule
     directly, so they keep their nowrap. */
  white-space: normal;
}
.pm-materials-toggle .text-muted { font-weight: 400; }
.me-item-photo-actions .btn-text { font-size: 11px; padding: 0; }
.me-item-award-pick .btn-text { font-size: 11px; margin-left: 6px; }
.quote-file-list .btn-text { padding: 0; font-size: 12px; }
/* Every part of the cell gets its own line: the button carries a long label and
   sits under whatever it is adding to, not beside it. */
.quote-file-cell > .text-muted,
.quote-file-cell .quote-file-attach { display: block; }
.me-stage-step.active { background: var(--accent); color: #fff; }
.catalog-picker { position: relative; flex: 1; max-width: 420px; }
.catalog-picker-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 20;
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-top: none;
  border-radius: 0 0 var(--radius) var(--radius);
  max-height: 280px;
  overflow-y: auto;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.14);
}
.catalog-picker-result {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  cursor: pointer;
  font-size: 12.5px;
  border: none;
  border-bottom: 1px solid var(--border);
  background: none;
  color: var(--text);
}
.catalog-picker-result:last-child { border-bottom: none; }
.catalog-picker-result:hover, .catalog-picker-result.active { background: var(--accent-tint); }
.catalog-picker-result .cp-sub { display: block; color: var(--text-muted); font-size: 11px; margin-top: 1px; }
.catalog-picker-empty { padding: 10px; color: var(--text-muted); font-size: 12.5px; }
/* A picker standing in for a full-width form field (the Material Request
   project search) rather than sitting inline in an add-item row. */
.catalog-picker-block { max-width: none; display: block; }
.picked-project .btn { margin-left: auto; font-weight: 500; }
.footer-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding-top: 6px;
}
/* ---------- Modal ---------- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(20, 26, 33, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}
.modal {
  background: #fff;
  border-radius: var(--radius);
  padding: 20px;
  width: 460px;
  max-width: calc(100vw - 40px);
  max-height: calc(100vh - 60px);
  overflow: auto;
  box-shadow: 0 8px 30px rgba(0,0,0,0.18);
}
.modal h2 { margin: 0 0 14px; font-size: 15px; }
.modal .footer-actions { margin-top: 16px; }
.modal-large {
  width: 720px;
  max-width: calc(100vw - 40px);
}
/* The manual project content editor — seven columns, and the two that matter
   most (Unit Cost and Amount) are the last ones, so at .modal-large's width
   they sit off the right edge behind a horizontal scroll nobody thinks to
   use. Wide enough that the whole line is visible at once. */
.pmi-modal {
  width: 980px;
  max-width: calc(100vw - 40px);
}
.kickoff-reschedule .field { flex: 0 0 auto; }
/* The one button is the card's action and sits at the end; Delete is a text
   link at the far side, where a destructive control is hard to hit by accident. */
.kickoff-card-open > .btn { margin-left: auto; }
.kom-facts span.text-muted { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
.kom-facts .btn-text { padding: 0; font-size: 11.5px; align-self: flex-start; }
.kom-topic .field { margin: 10px 0 0 34px; }
.kom-bar-id .btn-text { padding: 0; align-self: flex-start; font-size: 12px; }
.kom-bar-id .text-muted { font-size: 12px; }
.kom-bar-clock .text-muted { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.05em; }
.kom-attendance-who .text-muted { font-size: 12px; }
.kom-check-body .field { margin-left: 0; margin-top: 12px; }
.kom-reason-box .text-muted { font-size: 12px; }
.kom-action-what .text-muted { font-size: 11.5px; }
.kom-action-late .kom-action-what .text-muted { color: var(--danger); }
.kom-locked .text-muted { font-size: 12.5px; }
.kom-register .btn-text { padding: 0; text-align: left; }
.kom-minutes .kom-agenda-actions a.btn { text-decoration: none; }
.kom-sign-box .text-muted, .kom-sign-box .text-faint { font-size: 12px; }
.kom-sign-box .field { margin: 4px 0 0; }
.kom-sign-box .btn { align-self: flex-start; margin-top: 6px; }
@media (max-width: 640px) {
  /* The indent under a topic buys nothing on a phone and costs a third of the
     width of every notes field. */
  .kom-topic-guidance, .kom-topic .field, .kom-scope, .kom-scope-empty { margin-left: 0; }
  .kom-template-row { flex-wrap: wrap; }
  .kom-template-fields { flex: 1 1 100%; }
}
.chat-popup-channel-item.active { background: var(--accent-tint); }
.comment-action.active { color: var(--accent); }
/* ============================== Asset Management ============================== */

/* Selects and date pickers inherit width:100% from the base form styling,
   which stacks them one per row inside a toolbar. The base .toolbar rule only
   sizes text inputs, so scope the fix to this module rather than change a rule
   every other page shares. */
#am-tab-area .toolbar select,
#am-tab-area .toolbar input[type="month"],
#am-tab-area .toolbar input[type="date"] {
  width: auto;
  min-width: 130px;
  max-width: 220px;
}
#am-tab-area .toolbar label {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.am-batch-line .form-grid { margin: 0; }
@media print {
  .am-kpi-grid, .toolbar, .am-sigpad-wrap { display: none !important; }
}
/* ============================================================================
 * HR & Office Admin
 * Mirrors the .am-* conventions above; kept under its own prefix so the two
 * modules can diverge without either one having to inherit the other's tweaks.
 * ==========================================================================*/

/* Same trap as the Asset Management block above: selects and date pickers
   inherit width:100% from the base form styling, so an unscoped toolbar stacks
   them one per row. The base .toolbar rule only sizes text inputs. */
#hr-tab-area .toolbar select,
#hr-tab-area .toolbar input[type="date"] {
  width: auto;
  min-width: 140px;
  max-width: 230px;
}
.hr-kpi { padding: 12px 14px; margin: 0; }
.hr-kpi[data-hr-kpi]:hover {
  border-color: var(--accent);
  background: var(--accent-tint);
}
.hr-grid-3 .span-2 { grid-column: span 2; }
@media (max-width: 760px) {
  .hr-grid-3 { grid-template-columns: 1fr; }
  .hr-grid-3 .span-2, .hr-grid-3 .span-3 { grid-column: span 1; }
  .hr-emp-head { flex-wrap: wrap; }
}
.hr-grid-4 .span-2 { grid-column: span 2; }
.btn-icon.active { background: var(--accent); color: #fff; border-color: var(--accent); }
.pol-tree li.active { background: var(--accent-tint); border-left-color: var(--accent); font-weight: 600; }
@media (max-width: 760px) {
  .hr-grid-4 { grid-template-columns: 1fr; }
  .hr-grid-4 .span-2, .hr-grid-4 .span-4 { grid-column: span 1; }
  /* Before/after stacks rather than shrinking to two unreadable columns —
     comparing 30 characters per line against 30 characters is not comparing. */
  .pol-diff-cols { grid-template-columns: 1fr; }
  .pol-diff-before { border-right: none; border-bottom: 1px solid var(--border); }
  .pol-ack-list li { flex-direction: column; align-items: flex-start; }
  .pol-ack-actions { width: 100%; justify-content: flex-end; }
  .pol-reader-bar { flex-wrap: wrap; }
  .pol-chapter { padding: 0 10px; }
  .pol-subnav { gap: 4px; }
}
/* Selects and date inputs inherit width:100% from the global form rule, which
   in a flex .toolbar makes each one claim its own row. Size them to content
   so the filter bar stays a single line. */
#eng-search { width: 260px; }
.po-imp-supplier-head .text-muted { font-size: 11px; }
/* ---------- Official Business Trip ---------- */
/*
   The form's tab strip. Eight tabs do not fit across a phone, and the shared
   .toolbar wraps them onto four stacked rows that push the form off the
   screen. Here they scroll sideways instead — one row, always, with the
   active tab kept visible. Only this strip opts out of wrapping; every other
   .toolbar in the module (filters, row actions) keeps the shared behaviour.
*/
.obt-tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 4px;
}
.obt-tabs .chip {
  flex: 0 0 auto;
  scroll-snap-align: start;
}
/* The repeating tables (itinerary, transport legs, cost breakdown) carry up to
   twelve columns. They already scroll inside .table-scroll; this stops each
   cell's control from collapsing to an unusable width while they do. */
.obt-tabs ~ #obt-form-body .tabular input[type="text"],
.obt-tabs ~ #obt-form-body .tabular input[type="tel"],
.obt-tabs ~ #obt-form-body .tabular input[type="email"],
.obt-tabs ~ #obt-form-body .tabular input[type="url"],
.obt-tabs ~ #obt-form-body .tabular select {
  min-width: 130px;
  width: 100%;
}
.fb-intro .text-muted { display: block; max-width: 70ch; font-size: 12.5px; line-height: 1.55; }
.fb-intro .btn { flex: 0 0 auto; white-space: nowrap; }
/* Overriding .card h2, which is the app's uppercase section heading. This one
   is a sentence somebody typed, and shouting it back at them is not the same
   sentence. */
.fb-post-head h2 {
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text);
}
.fb-nudge .btn { flex: 0 0 auto; }
.fb-quick-head .text-muted { font-size: 11px; }
.fb-quick-head .btn-text { margin-left: auto; }
/* The pickers are <label>s for hidden file inputs, so they need the button's
   own geometry rather than inheriting it. */
.vi-photo-add label.btn {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}
.vi-photo-add .btn.disabled {
  opacity: 0.5;
  pointer-events: none;
}
/* "Take photo" is only a real choice on a device with a camera. On a mouse
   machine `capture` is ignored and the button would open a second file dialog
   identical to the gallery one, so it is hidden rather than misleading.

   Both selectors have to out-specify `.vi-photo-add label.btn` above (0-2-1),
   or the base display wins and the button shows everywhere. */
.vi-photo-add label.btn.vi-photo-camera { display: none; }
@media (pointer: coarse) {
  .vi-photo-add label.btn.vi-photo-camera { display: inline-flex; }
}
.vi-photo figcaption .btn-text { align-self: flex-start; }
/* ---------- The checklist on a phone ----------

   This form is filled in standing next to the vehicle, so the handset layout
   is the one that has to work, not a fallback. Below 760px the five-column
   table becomes one card per item: the heading row is dropped, each answer
   prints its own column label from the data-label attribute set in
   public/vehicles.js, and the row number moves inline with the item text.

   .table-scroll goes back to visible overflow here — a card list has nothing
   to scroll sideways, and leaving it on traps the page in a 1px horizontal
   drag. */

@media (max-width: 760px) {
  .vi-table-wrap { overflow-x: visible; }

  .vi-table,
  .vi-table tbody,
  .vi-table tr,
  .vi-table td {
    display: block;
    width: 100%;
    box-sizing: border-box;
  }

  .vi-table thead { display: none; }

  .vi-table .vi-section-row td {
    border-radius: var(--radius);
    margin: 14px 0 8px;
    padding: 6px 10px;
    border-bottom: none;
  }

  .vi-item-row {
    border: 1px solid var(--border);
    border-left-width: 3px;
    border-left-color: var(--border-strong);
    border-radius: var(--radius);
    margin-bottom: 10px;
    padding: 10px 12px;
    background: var(--panel);
  }

  /* On a card the verdict colours the whole left edge, so the desktop rule
     that puts it on the first cell has nothing to attach to. */
  .vi-item-row.vi-pass { border-left-color: var(--success); }
  .vi-item-row.vi-attention { border-left-color: var(--warn); }
  .vi-item-row.vi-fail { border-left-color: var(--danger); }
  .vi-item-row.vi-na { border-left-color: var(--border-strong); }
  .vi-item-row td:first-child { border-left: none; }

  .vi-item-row td {
    border-bottom: none;
    padding: 0 0 8px;
  }
  .vi-item-row td:last-child { padding-bottom: 0; }

  .vi-item-row .vi-seq { display: none; }
  .vi-seq-inline { display: inline; color: var(--text-faint); }

  .vi-item-row .vi-what {
    font-weight: 600;
    font-size: 13px;
    padding-bottom: 8px;
  }

  .vi-item-row td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 3px;
  }

  /* Tap targets. 16px on the controls is also what stops iOS Safari zooming
     the whole page in the moment a field takes focus. */
  .vi-table select,
  .vi-table input[type="text"],
  .vi-table input[type="date"] {
    font-size: 16px;
    padding: 8px 8px;
  }

  /* The two list screens become one card per row, same technique as the
     checklist. A ten-column table on a handset is a sideways drag looking for
     a column you cannot see the heading of. */
  .vi-list-wrap { overflow-x: visible; max-height: none !important; }

  .vi-list,
  .vi-list tbody,
  .vi-list tr,
  .vi-list td {
    display: block;
    width: 100%;
    box-sizing: border-box;
  }

  .vi-list thead { display: none; }

  .vi-list-row {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 10px;
    padding: 10px 12px;
    background: var(--panel);
  }

  .vi-list-row td {
    border-bottom: none;
    padding: 2px 0;
    white-space: normal;
    text-align: left;
  }

  .vi-list-row .vi-list-head {
    font-size: 15px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 6px;
  }
  .vi-list-row .vi-list-head .btn-text { font-size: 15px; }

  /* Label and value on one line: these are short facts, and stacking them
     would make a ten-row card twice as long as it needs to be. */
  .vi-list-row td[data-label] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 4px 12px;
    /* A value with a second line under it (the colour and body type below the
       model) wraps onto its own row rather than running off the card. */
    flex-wrap: wrap;
  }

  .vi-list-row td[data-label] > * { min-width: 0; }

  .vi-list-row td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-size: 11px;
    color: var(--text-muted);
  }

  .vi-photo-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
  .vi-photo img { height: 110px; }
  .vi-photo figcaption input { font-size: 16px; }

  .vi-summary { padding: 10px; }
  .vi-find ul { padding-left: 16px; }

  /* One control per line beats four half-width ones a thumb cannot hit. The
     flex reset is not optional: .vi-grow's `flex: 1 1 240px` is a MAIN-axis
     rule, and in a column it stretches the search box to 240px TALL. It has to
     be overridden with the same selector — a media query adds no specificity,
     so `.vi-toolbar > *` would lose to `.vi-toolbar .vi-grow`. */
  .vi-toolbar { flex-direction: column; align-items: stretch; }
  .vi-toolbar > * { width: 100%; }
  .vi-toolbar .vi-grow { flex: 0 0 auto; }
  .vi-toolbar label { display: flex; align-items: center; gap: 6px; }
  .vi-toolbar label input { flex: 1; }
  .vi-toolbar select,
  .vi-toolbar input { font-size: 16px; }

  /* The signature pad sits beside its Clear button, which on a handset leaves
     a strip too narrow to sign in. Stack them so the pad gets the full width.
     Applies to every pad in Asset Management — endorsements and returns are
     signed on a phone for the same reason inspections are. */
  .am-sigpad-wrap { flex-direction: column; align-items: stretch; }
  .am-sigpad { height: 120px; }
  .am-sigpad-wrap .btn { align-self: flex-end; }
}
.dar-nte-banner .btn { flex: 0 0 auto; }
@media (max-width: 700px) {
  .dar-nte-banner .btn { width: 100%; }
}
.sr-dar-bar .text-muted { font-size: 0.85rem; }
/* ONE scroll region, not two. `.modal` already scrolls at
   calc(100vh - 60px), and a list with its own max-height inside it gives a
   fourteen-line day two nested scrollbars — a phone flicks the wrong one
   every time. The head stays put instead, so the select-all box and the
   count are still reachable at the bottom of a long day. */
.sr-dar-list { border: 1px solid var(--border); border-radius: var(--radius); }
@media (max-width: 700px) {
  .sr-narrative, .sr-narrative-print { grid-template-columns: 1fr; }
  .sr-toolbar-actions { margin-left: 0; width: 100%; }
  .sr-toolbar-actions .btn { flex: 1 1 auto; }
}
.sr-add-rec-actions .btn { margin-left: auto; }
@media (max-width: 700px) {
  .sr-add-rec-actions .btn { margin-left: 0; flex: 1 1 100%; }
}
.sr-actions .btn { min-height: 44px; }
.sr-punchbar .btn { min-height: 46px; padding-left: 22px; padding-right: 22px; font-weight: 600; }
@media (max-width: 700px) {
  .sr-punchbar .btn { flex: 1 1 100%; }
  .sr-punchbar select, .sr-punch-label { flex: 1 1 100%; }
}
.dar-add-row .btn { flex: 0 0 auto; white-space: nowrap; }
@media screen and (max-width: 760px) {
  /* On a phone the refinements go under the title rather than beside it, and
     the button spans the row so it is a thumb target. */
  .dar-add-input { flex: 1 1 100%; }
  .dar-add-row select, .dar-add-row input[type="date"] { flex: 1 1 46%; min-width: 0; max-width: none; }
  .dar-add-row .btn { flex: 1 1 100%; }
}
/* And the two filter dropdowns beside it — .toolbar sizes text inputs but says
   nothing about selects, so they inherit the same full-width basis. */
.dar-backlog-toolbar select { flex: 0 0 auto; width: auto; min-width: 9rem; }
.dar-chip-danger.active { background: var(--danger); border-color: var(--danger); color: #fff; }
.dar-chip-warn.active { background: var(--warn); border-color: var(--warn); color: #fff; }
.dar-quick-add .btn { flex: 0 0 auto; }
.dar-weekday.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.dar-template-add .btn { flex: 0 0 auto; }
.dar-comment-form .btn { flex: 0 0 auto; }
.dar-team-tab.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.dar-team-tab-summary:not(.active) { border-color: var(--border-strong); }
.dar-today-table .text-muted { font-size: 11px; }
.dar-day-date .text-muted { font-size: 11px; }
@media screen and (max-width: 760px) {
  /* Rule 4 of dar.js: this screen is used one-handed, before 8:30, on mobile
     data. The submit button follows the thumb rather than sitting at the
     bottom of a scrolled page. */
  .dar-submit-card {
    position: sticky; bottom: 0; z-index: 5;
    border-top: 1px solid var(--border-strong); box-shadow: 0 -2px 6px rgba(0,0,0,0.06);
  }
  .dar-submit-card .btn-primary { width: 100%; }
  .dar-countdown { position: sticky; top: 0; z-index: 5; }
  .dar-modal { padding: 0; }
  .dar-modal-box { max-height: 100vh; border-radius: 0; }
}
/* ==================== Finance → Client POs ====================

   The register of purchase orders received from clients, and the form the
   file reader fills in. Almost all of this screen is built from classes that
   already exist — .form-grid, .card, .chip, the plain table — because it IS an
   ordinary register. What is new here is the small vocabulary for the one
   thing that has no precedent in this app: a field whose value was read off a
   photograph by a machine and needs a person to confirm it.

   That vocabulary is deliberately quiet. A machine-read PO is right most of
   the time, and shouting about every field would train people to click past
   the warning on the one field that matters.

   The Bank Cheque register on the tab beside it reads a document the same
   way, so it shares this vocabulary rather than growing a second one that
   drifts: every rule below is written for both prefixes. */

.cpo-warn,
.bcq-warn {
  margin-top: 6px;
  padding: 6px 9px;
  border-left: 3px solid var(--warn);
  background: var(--warn-tint);
  color: var(--warn);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 12px;
  line-height: 1.45;
}
.cpo-picked .btn-text,
.bcq-picked .btn-text,
.ep-picked .btn-text { margin-left: auto; white-space: nowrap; }
/* The picker inside a form field is a block, not a toolbar control, so it
   takes the field's width rather than .catalog-picker's flex sizing. */
.cpo-picked, .bcq-picked, .ep-picked, .catalog-picker.catalog-picker-block { width: 100%; }
/* These carry `display` on a class, which beats the browser's own [hidden]
   rule — so `el.hidden = true` left BOTH halves on screen: an empty bordered
   box above the search field, and the search field still there under the
   chosen value after you picked one. The swap is the whole mechanism, so it
   has to be stated here rather than left to the UA stylesheet. */
.cpo-picked[hidden],
.bcq-picked[hidden],
.ep-picked[hidden],
.catalog-picker[hidden],
.entity-picker[hidden] { display: none; }
/* A filter that sits in a form-grid cell (Purchase Orders' filter card) takes
   the cell, like the date and select controls beside it. The capped width is
   for a filter sitting loose in a flex .toolbar, where nothing else bounds it. */
.field > .entity-picker-filter,
.form-grid .entity-picker-filter { width: 100%; min-width: 0; max-width: none; }
.entity-picker-filter .ep-picked .btn-text {
  font-size: 15px;
  line-height: 1;
  padding: 0 2px;
}
td .entity-picker .catalog-picker { max-width: none; }
/* ===================== Invoicing =====================
   The Finance page's fourth register. Three things here are not reused from
   anywhere else because nothing else in the app looks like them: the two-pane
   filing form (the booklet copy on one side, the fields on the other, so the
   encoder types straight off the image), the serial grid, and the deductions
   ladder. Everything else on those screens is the ordinary card/table/badge
   vocabulary. */

/* Three general utilities, introduced here because this module needed them
   and the file already carries .text-muted / .text-right / .text-faint beside
   them. `.small` replaces the inline font-size:12px the older modules repeat. */
.text-ok { color: var(--success); }
/* `.field` sets display:flex, which outranks the browser's own [hidden]
   rule — so a field toggled with the hidden attribute (the petty cash box on
   an expense claim, the employee picker on a payment request) stayed visible.
   Same fix, same reason, as .chip-badge[hidden] above. */
.field[hidden] { display: none !important; }
.row-actions .btn { margin-left: 4px; }
.tpl-offer .text-muted { font-size: 12px; }
.tpl-apply-row.active { border-color: var(--accent); background: var(--accent-tint); }
.tpl-apply-row .text-muted { font-size: 11.5px; }
.tpl-apply-mode .field label { display: block; }
.tpl-person .text-muted { font-size: 12px; }
.modal .toolbar-search { max-width: none; width: 100%; margin: 8px 0 0; }
/* ==================== Engineering → Solar PV System Designer ====================

   Almost nothing, and deliberately: the catalog manager is built from the
   pieces that already exist — .card, .toolbar, .tab-strip .chip, the plain
   table, .form-grid, .badge-*. What is here is the handful of things those do
   not cover. See web/SOLAR-PV.md. */

/* A checkbox that sits ON the toolbar beside the search box, rather than in a
   .field with a label above it. */
.pv-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-muted);
  white-space: nowrap;
}
.pv-actions .btn { margin-left: 4px; }
@media (max-width: 760px) {
  .pv-actions { white-space: normal; }
  .pv-actions .btn { margin: 2px 0 0 4px; }
}
/* ====================== Company Profile Creator ======================
   Sales Department's fourth tab. Everything is namespaced .cp- so it cannot
   reach any other screen — note that .catalog-picker-result .cp-sub above is
   an unrelated older name, scoped to its own parent and untouched by these. */

.cp-intro {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  flex-wrap: wrap;
  margin: 12px 0 10px;
}
.cp-pane-head .text-muted { font-size: 11px; }
.cp-page-dot.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.cp-row-actions a.btn,
.cp-tile a.btn,
.cp-card-head a.btn { display: inline-flex; align-items: center; text-decoration: none; }
.el-row-actions .btn-text { margin-left: 8px; }
.el-preview-row > .text-muted { min-width: 74px; font-size: 12px; }
.task-actions-col .btn { margin-right: 4px; }
.cpd-type.active { border-color: var(--accent); background: var(--accent-tint); }
.cpd-sec.active { background: var(--accent); color: #fff; }
.cpd-sec.active .text-muted, .cpd-sec.active .cpd-sec-n { color: rgba(255, 255, 255, 0.75); }
.cpd-sec.active .cpd-mark.ok, .cpd-sec.active .cpd-mark.empty { color: #fff; }
.cpd-pane > .card { margin: 0; }
.cpd-node-text .text-muted { font-size: 10px; }
/* The bar sits at the right of the deck header. Buttons wrap rather than
   squeeze on a narrow window — a workflow button that has been squashed to
   three characters is a workflow button nobody presses. */
.cpd-card-head .btn { flex: none; }
.cpd-pdfs .text-muted { font-size: 11px; }
/* ==========================================================================
   Project Hub — one project, whole (public/project-hub.js, PROJECT-HUB.md).
   Cards reuse .card; the strip reuses .wf-cards; the flow bar is the Workflow
   tab's own .wf-bar. Only the header strip and the two-column grid are new.
   ========================================================================== */

.ph-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px 24px;
  margin-bottom: 16px;
}
.ph-grid > .card { margin: 0; }
/* ---------- Solar Survey (public/solar-survey.js) ---------- */
.ss-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
  margin: 10px 0 14px;
}
.ss-subtabs { margin-top: -6px; }
.ss-lists {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}
.ss-lists-nav .tab-strip { flex-wrap: wrap; margin-bottom: 8px; }
.ss-list-index {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 60vh;
  overflow: auto;
}
.ss-list-index li {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 8px;
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 13px;
}
.ss-list-index li:hover { background: var(--bg); }
.ss-list-index li.active { background: var(--accent-tint); color: var(--accent); font-weight: 600; }
.ss-rows .ss-order { white-space: nowrap; }
.ss-rows .ss-order .btn { padding: 2px 7px; }
.ss-row-archived td { color: var(--text-faint); }
.ss-row-archived code { color: var(--text-faint); }
.ss-city-head { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.ss-inline-form { display: flex; align-items: center; gap: 6px; }
.ss-inline-form label { font-size: 12px; color: var(--text-muted); }
.ss-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.ss-util select { max-width: 100%; }
@media (max-width: 760px) {
  .ss-lists { grid-template-columns: 1fr; }
  .ss-list-index { max-height: 40vh; }
}
.ss-toolbar select { max-width: 340px; }
.ss-toolbar input[type="text"] { max-width: 340px; }
/* ---------- Solar Survey form (public/ss-form.js) — mobile first ---------- */
.ss-form { max-width: 760px; margin: 0 auto; }
.ss-form-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 8px; }
.ss-form-title { flex: 1; min-width: 0; }
.ss-form-sub { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ss-locked { background: var(--warn-tint); color: var(--warn); border-radius: var(--radius); padding: 8px 12px; font-size: 13px; margin-bottom: 8px; }
.ss-steps { display: flex; gap: 6px; overflow-x: auto; padding: 4px 0 8px; scrollbar-width: none; position: sticky; top: 0; background: var(--bg); z-index: 5; }
.ss-steps::-webkit-scrollbar { display: none; }
.ss-step-btn { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border-strong); background: #fff; border-radius: 999px; padding: 6px 12px 6px 6px; font-size: 12px; cursor: pointer; white-space: nowrap; }
.ss-step-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
.ss-step-no { display: inline-flex; width: 22px; height: 22px; border-radius: 50%; background: var(--accent-tint); color: var(--accent); align-items: center; justify-content: center; font-weight: 700; font-size: 11px; }
.ss-step-btn.active .ss-step-no { background: #fff; }
.ss-step-body .card { margin-bottom: 12px; }
.ss-step-body h3 { margin: 0 0 10px; font-size: 14px; }
.ss-step-nav { display: flex; justify-content: space-between; gap: 10px; padding: 10px 0 24px; position: sticky; bottom: 0; background: var(--bg); }
.ss-step-nav .btn { min-height: 44px; flex: 1; }
.ss-field { margin-bottom: 14px; }
.ss-field-label { font-size: 12px; font-weight: 600; color: var(--text-muted); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.02em; }
.ss-req { color: var(--danger); }
.ss-hint { font-weight: 400; text-transform: none; letter-spacing: 0; font-size: 11px; }
.ss-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ss-chips .chip { min-height: 36px; font-size: 13px; padding: 6px 12px; }
.ss-chip-other { border-style: dashed; }
.ss-other-box { margin-top: 6px; }
.ss-other-box input { width: 100%; min-height: 40px; }
.ss-stepper { display: inline-flex; flex: 0 0 auto; align-items: stretch; border: 1px solid var(--border-strong); border-radius: 10px; overflow: hidden; background: #fff; }
.ss-stepper .btn { border: 0; border-radius: 0; min-width: 44px; min-height: 42px; justify-content: center; font-size: 20px; line-height: 1; padding: 0; background: var(--panel, #f4f6f9); }
.ss-stepper .btn:first-child { border-right: 1px solid var(--border-strong); }
.ss-stepper .btn:last-child { border-left: 1px solid var(--border-strong); }
.ss-stepper-value { display: inline-flex; align-items: center; justify-content: center; min-width: 72px; padding: 0 10px; font-weight: 600; font-size: 15px; }
.ss-dist { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ss-dist select { flex: 1; min-width: 180px; min-height: 44px; font-size: 15px; }
.ss-dist .ss-pick { flex: 1; min-width: 180px; }
.ss-numpad { display: flex; align-items: center; gap: 6px; }
.ss-numpad input { flex: 1; min-height: 44px; font-size: 16px; }
.ss-unit { color: var(--text-muted); font-size: 13px; white-space: nowrap; }
.ss-inline { display: flex; gap: 6px; align-items: center; }
.ss-inline input { flex: 1; min-height: 44px; }
.ss-toggle-btn { display: inline-flex; align-items: center; gap: 8px; border: 1px solid var(--border-strong); background: #fff; border-radius: 999px; padding: 6px 12px 6px 6px; cursor: pointer; font-size: 13px; min-height: 36px; }
.ss-toggle-knob { width: 34px; height: 20px; border-radius: 999px; background: var(--border-strong); position: relative; transition: background 0.15s; }
.ss-toggle-knob::after { content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: left 0.15s; }
.ss-toggle-btn.on .ss-toggle-knob { background: var(--success); }
.ss-toggle-btn.on .ss-toggle-knob::after { left: 16px; }
.ss-form select, .ss-form input[type="text"], .ss-form input[type="tel"], .ss-form input[type="email"], .ss-form textarea { width: 100%; min-height: 44px; font-size: 16px; }
.ss-cascade { display: grid; grid-template-columns: 1fr; gap: 0 12px; }
.ss-locate { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.ss-locate .btn { min-height: 44px; }
.ss-picked { display: flex; align-items: center; gap: 10px; justify-content: space-between; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); margin-bottom: 8px; }
.ss-new-client { margin-top: 10px; padding: 10px; border: 1px dashed var(--border-strong); border-radius: var(--radius); }
.ss-warn { border-left: 4px solid var(--warn); }
.ss-dictate-tools { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.ss-dictate textarea[readonly] { background: var(--bg); }
.ss-kwh input { width: 100%; min-width: 80px; min-height: 40px; font-size: 15px; }
.ss-kwh td, .ss-kwh th { padding: 4px 6px; }
.ss-load-grid { display: grid; grid-template-columns: 1fr; gap: 6px; }
.ss-load-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.ss-scan { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.ss-confirm-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 14px; }
.ss-confirm-row span { flex: 1; }
.ss-photo-cats { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
.ss-photo-cat { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 12px 6px; border: 1px solid var(--border-strong); border-radius: var(--radius); background: #fff; cursor: pointer; font-size: 12px; min-height: 84px; position: relative; }
.ss-photo-cat.has { border-color: var(--success); background: var(--success-tint); }
.ss-photo-cat.need { border-color: var(--danger); }
.ss-photo-cat-icon { font-size: 22px; }
.ss-photo-cat-n { position: absolute; top: 6px; right: 8px; font-weight: 700; color: var(--success); }
.ss-photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 8px; }
.ss-photo { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; cursor: pointer; background: #fff; }
.ss-photo img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.ss-photo.excluded img { opacity: 0.4; }
.ss-photo-cap { font-size: 11px; padding: 4px 6px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ss-photo-editor { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.ss-photo-editor > img { width: 100%; max-height: 50vh; object-fit: contain; background: #111; border-radius: var(--radius); margin-bottom: 10px; }
.ss-facts th { text-align: left; width: 34%; color: var(--text-muted); font-weight: 600; font-size: 12px; padding: 5px 6px; vertical-align: top; }
.ss-facts td { padding: 5px 6px; font-size: 13px; }
.ss-problem-group { margin-bottom: 10px; }
.ss-problem-group ul { margin: 4px 0 0; padding-left: 18px; font-size: 13px; }
.ss-list-card { display: flex; justify-content: space-between; gap: 10px; align-items: center; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: #fff; margin-bottom: 8px; cursor: pointer; }
.ss-list-card:hover { background: var(--bg); }
.ss-list-card .ss-list-main { min-width: 0; }
.ss-list-card .ss-list-sub { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (min-width: 640px) {
  .ss-cascade { grid-template-columns: 1fr 1fr; }
  .ss-load-grid { grid-template-columns: 1fr 1fr; }
}
.turnover-actions .btn { margin: 1px 0; }
/* ---------- Solar Survey map step (public/ss-map.js) ---------- */
.ss-map-wrap { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: #111; margin-bottom: 12px; }
.ss-map-wrap.ss-map-full { position: fixed; inset: 0; z-index: 120; border: 0; border-radius: 0; margin: 0; }
.ss-map-bar { display: flex; align-items: center; gap: 8px; padding: 6px 8px; background: #fff; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.ss-map-canvas { position: relative; height: 52vh; min-height: 320px; background: #222; }
.ss-map-full .ss-map-canvas { flex: 1; height: auto; }
.ss-map-nokey { position: absolute; inset: 12px auto auto 12px; right: 12px; background: rgba(255,255,255,0.95); padding: 10px 12px; border-radius: var(--radius); font-size: 13px; z-index: 2; }
.ss-map-tools { display: flex; gap: 6px; padding: 6px 8px; background: #fff; border-top: 1px solid var(--border); flex-wrap: wrap; align-items: center; }
.ss-map-tools .chip.active { background: var(--accent); color: #fff; border-color: var(--accent); }
.ss-map-hint { font-size: 12px; color: var(--accent); font-weight: 600; }
.ss-slider { display: flex; align-items: center; gap: 10px; }
.ss-slider input[type="range"] { flex: 1; min-height: 32px; }
.ss-slider span { min-width: 36px; font-weight: 700; text-align: right; }
.ss-segments { display: grid; grid-template-columns: 1fr; gap: 6px; }
.ss-segment { display: flex; align-items: center; gap: 10px; text-align: left; border: 1px solid var(--border-strong); border-radius: var(--radius); background: #fff; padding: 8px 10px; cursor: pointer; font-size: 13px; opacity: 0.55; }
.ss-segment.on { opacity: 1; border-color: var(--accent); }
.ss-seg-swatch { display: inline-block; width: 14px; height: 14px; border-radius: 3px; flex: 0 0 auto; }
.ss-mseg { border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 10px; margin-bottom: 8px; background: #fff; }
.ss-mseg.active { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
.ss-mseg-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; margin-bottom: 6px; }
.ss-measure { padding: 8px 10px; background: var(--accent-tint); border-radius: var(--radius); font-size: 13px; }
.ss-sensor-reading { font-size: 44px; font-weight: 700; text-align: center; padding: 16px 0; color: var(--accent); }
@media (min-width: 640px) { .ss-segments { grid-template-columns: 1fr 1fr; } }
.ss-warn-text { color: var(--warn); font-size: 13px; }
@media (max-width: 700px) {
  /* Stack the row, and let the buttons run full width — Done and Snooze are
     the two things this screen exists for and they should be easy to hit. */
  ul.crm-fulist > li { flex-direction: column; align-items: stretch; gap: 8px; }
  .crm-fu-actions > .btn { flex: 1 1 auto; }
  .crm-snooze > .btn { flex: 1 1 auto; }
}
.ss-map-find { min-width: 200px; max-width: 320px; }
.ss-map-find input { min-height: 32px; font-size: 13px; }
.ss-list-toolbar input[type="text"] { min-width: 220px; flex: 1; }
.ss-filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 8px; margin: 8px 0; }
.ss-filter-grid select, .ss-filter-grid input { width: 100%; min-height: 36px; }
.ss-date { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.ss-list-actions { line-height: 1.6; }
.ss-list-actions .btn-text { font-size: 12px; }
.ss-draft-chips { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.chip.chip-primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.chip[disabled] { opacity: 0.45; cursor: default; }
/* Solar Survey: every choice is a dropdown; multi-choice lists show their picks as removable tags. */
.ss-pick { display: block; }
.ss-pick select, #ss-companions select { width: 100%; min-height: 44px; font-size: 15px; }
.ss-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.ss-tag .ss-tag-x { margin-left: 6px; opacity: 0.8; font-weight: 700; }
.turnover-filters .field { margin: 0; }
.turnover-filter-clear .btn { width: 100%; }
/* Solar Survey: cable runs table and the guided measure */
.ss-runs { width: 100%; border-collapse: collapse; margin-top: 4px; }
.ss-runs td { padding: 8px 6px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.ss-runs tr:last-child td { border-bottom: 0; }
.ss-runs-val { white-space: nowrap; font-weight: 600; text-align: right; }
.ss-runs-act { text-align: right; white-space: nowrap; }
.ss-measure { background: var(--panel, #f4f6f9); border: 1px solid var(--border-strong); border-radius: 10px; padding: 12px; }
.ss-measure-title { margin-bottom: 8px; }
.ss-measure-step { display: flex; align-items: center; gap: 10px; font-size: 15px; margin: 6px 0; }
.ss-step-no { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: var(--accent); color: #fff; font-weight: 700; flex: none; }
.ss-measure-choices { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 8px; }
.ss-measure-choices .btn { display: block; text-align: center; min-height: 60px; line-height: 1.3; }
.ss-measure-num { font-size: 18px; font-weight: 700; }
@media (max-width: 480px) { .ss-runs-act .btn { padding: 6px 8px; } }
/* Solar Survey: extra materials picker */
.ss-bos-pick { display: grid; grid-template-columns: minmax(160px, 1fr) 2fr; gap: 8px; margin-bottom: 8px; }
.ss-bos-label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.02em; }
.ss-bos-label select { min-height: 44px; font-size: 15px; text-transform: none; letter-spacing: 0; }
.ss-bos-line-tools { display: inline-flex; align-items: center; gap: 8px; }
@media (max-width: 600px) { .ss-bos-pick { grid-template-columns: 1fr; } }
.ss-dictate-lang { min-height: 32px; font-size: 13px; }
.ss-load-total { display: flex; justify-content: space-between; align-items: center; padding: 10px 6px; margin-top: 4px; border-top: 2px solid var(--border-strong); font-size: 15px; }
.ss-load-row-energy { flex-wrap: wrap; }
.ss-load-name { flex: 1 1 180px; }
.ss-load-tools { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ss-load-hours { flex: 1 1 140px; min-width: 140px; }
.ss-load-hours { min-height: 42px; font-size: 14px; }
.ss-load-total-energy { border-top: 1px dashed var(--border-strong); }
.ss-pick-search input { width: 100%; min-height: 44px; font-size: 15px; }
.ss-pick-search .catalog-picker-results { max-height: 320px; overflow-y: auto; }
.ss-pick-search .catalog-picker-result.ss-chip-other { border-top: 1px dashed var(--border-strong); }
.ss-source-sheet { max-width: 420px; }
.ss-source-choices { display: grid; gap: 10px; margin: 8px 0 4px; }
.ss-source-choices .btn { min-height: 52px; font-size: 16px; justify-content: center; }
.ss-plane-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 6px 0; border-bottom: 1px solid var(--border); }
.ss-plane-row:last-child { border-bottom: 0; }
.ss-plane-name { min-width: 120px; }
.ss-plane-select { min-height: 40px; font-size: 14px; flex: 1; min-width: 140px; }
.ss-rotate { display: inline-flex; align-items: center; gap: 2px; }
.ss-rotate .btn { min-height: 36px; padding: 0 8px; font-size: 12px; }
.ss-rotate .ss-stepper-value { min-width: 78px; font-size: 13px; }

/* =========================================================================
 * The PV System Designer
 * =======================================================================
 * A design page is denser than the rest of the app, and deliberately so: an
 * engineer comparing three sizing options wants them side by side, and the
 * bill of materials is a table nobody wants to scroll one line at a time.
 * Everything below still starts as one column — the drawings especially, which
 * are wide and scroll inside their own frame rather than pushing the page.
 */

.design-head {
  display: flex; align-items: flex-start; gap: 12px; margin: 0 0 14px;
}
.design-head h1 { margin: 0 0 3px; }
.design-head-right { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }

.tag.warn { background: var(--sun-lite); color: #6b4a10; }

.design-stats { margin: 0 0 16px; }
.design-stats .stat.bad { background: var(--red-lite); border-color: #f2cdc9; }
.design-stats .stat.bad .n { color: #7c1b15; }

.subtabs {
  display: flex; gap: 4px; overflow-x: auto; margin: 0 -18px 16px; padding: 0 18px 2px;
  border-bottom: 1px solid var(--line);
  -webkit-overflow-scrolling: touch;
}
.subtabs button {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer;
  padding: 10px 14px; font: inherit; font-size: .93rem; color: var(--ink-soft);
  border-bottom: 2px solid transparent; white-space: nowrap;
}
.subtabs button.on { color: var(--green-mid); border-bottom-color: var(--green-mid); font-weight: 600; }

/* --- fields laid out in a grid ------------------------------------------ */

.field-grid { display: grid; gap: 0 16px; grid-template-columns: 1fr; }
@media (min-width: 700px) { .field-grid { grid-template-columns: 1fr 1fr; } }
.field-grid .field.grow { grid-column: 1 / -1; }
.field.check label { display: flex; align-items: center; gap: 9px; font-weight: 500; }
.field.check input[type=checkbox] { width: 18px; height: 18px; }

/* --- facts: a small key/value block ------------------------------------- */

.facts { display: grid; gap: 6px 18px; margin: 12px 0; grid-template-columns: 1fr; }
@media (min-width: 620px) { .facts { grid-template-columns: 1fr 1fr; } }
.facts > div { display: flex; gap: 10px; justify-content: space-between;
  border-bottom: 1px dotted var(--line); padding: 4px 0; font-size: .92rem; }
.facts .k { color: var(--ink-faint); }
.facts .v { font-weight: 600; text-align: right; }
.big-facts > div { font-size: 1rem; padding: 7px 0; }

/* --- findings ------------------------------------------------------------ */

.findings { display: grid; gap: 8px; margin: 12px 0 0; }
.finding {
  display: flex; gap: 10px; align-items: flex-start;
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 12px; font-size: .92rem; background: var(--card);
}
.finding .lv {
  flex: 0 0 auto; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  font-weight: 700; padding: 2px 7px; border-radius: 4px; margin-top: 1px;
}
.finding.block { background: var(--red-lite); border-color: #f2cdc9; color: #7c1b15; }
.finding.block .lv { background: #7c1b15; color: #fff; }
.finding.warn  { background: var(--sun-lite); border-color: #f2ddb5; color: #6b4a10; }
.finding.warn .lv { background: #6b4a10; color: #fff; }
.finding.info .lv { background: var(--line-soft); color: var(--ink-soft); }

/* --- the sizing table ---------------------------------------------------- */

.sizing-grid { display: grid; gap: 12px; grid-template-columns: 1fr; margin-top: 12px; }
@media (min-width: 900px) { .sizing-grid { grid-template-columns: repeat(3, 1fr); } }
.sizing {
  border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 14px;
  display: flex; flex-direction: column;
}
.sizing h3 { margin: 0 0 4px; }
.sizing.off { opacity: .65; }
.sizing .big { font-size: 1.9rem; font-weight: 700; color: var(--green); margin: 6px 0 2px; }
.sizing .facts { grid-template-columns: 1fr; }
.sizing .basis { font-size: .82rem; margin: 4px 0 10px; }
.sizing .btn { margin-top: auto; }

/* --- MPPT and array rows -------------------------------------------------- */

.mppt-row {
  display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end;
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px; margin: 0 0 10px;
}
.mppt-row .field { margin: 0; flex: 0 0 110px; }
.mppt-row .field.grow { flex: 1 1 220px; }
.mppt-row .btn { margin-bottom: 2px; }

/* --- the bill of materials ------------------------------------------------ */

table.grid.bill-grid input { width: 100%; min-width: 130px; }

table.grid.bom { font-size: .9rem; }
table.grid.bom .r { text-align: right; white-space: nowrap; }
table.grid.bom tr.group td {
  background: var(--line-soft); font-weight: 650; text-transform: capitalize;
  font-size: .82rem; letter-spacing: .03em;
}
table.grid.bom tr.overridden { background: var(--sun-lite); }
table.grid.bom .basis { font-size: .8rem; margin-top: 3px; line-height: 1.35; }
table.grid.bom .warn-text { color: #6b4a10; }
table.grid.bom .actions { white-space: nowrap; }

/* --- drawings ------------------------------------------------------------- */

.drawing-frame {
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow-x: auto; background: #fff; padding: 8px;
  -webkit-overflow-scrolling: touch;
}
.drawing-frame svg { display: block; min-width: 620px; height: auto; }

/* --- verification --------------------------------------------------------- */

.verify-list { margin-top: 12px; }
.verify-row {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  border-top: 1px solid var(--line); padding: 10px 0;
}
.verify-row span { font-weight: 600; }
.verify-row .btn { margin-left: auto; }

/* The save button sits at the bottom of a long form, where the thumb is. */
.sticky-save { position: sticky; bottom: 12px; z-index: 5; }
.sticky-save .btn { box-shadow: var(--shadow); }

/* =========================================================================
 * SolarQuoteExpert — the editor
 * =======================================================================
 * The quotation editor is a WORKING TABLE and it is meant to look like one:
 * input boxes in a grid, not a rendered document. That is not laziness, it is
 * the paywall. Everything on this screen is free, and what a credit buys is
 * the printed page with the letterhead on it — so the free screen must not
 * itself be a usable document. A screenshot of this is a screenshot of a
 * spreadsheet.
 */

.q-section { margin: 0 0 20px; }
.q-section-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0 0 6px;
}
.q-section-head h3 { margin: 0; font-size: 1rem; }
.q-section-head .spacer { flex: 1; }
.q-section-title {
  font: inherit; font-weight: 650; font-size: 1rem;
  border: 1px solid transparent; border-radius: 6px; padding: 4px 8px;
  background: transparent; min-width: 200px; color: var(--ink);
}
.q-section-title:hover { border-color: var(--line); }
.q-section-title:focus { border-color: var(--green-mid); background: var(--card); outline: none; }
.q-subtotal { font-weight: 650; }

table.grid.q-lines { font-size: .9rem; }
table.grid.q-lines .r { text-align: right; }
table.grid.q-lines td { vertical-align: top; }
table.grid.q-lines td.money { padding-top: 12px; white-space: nowrap; }
table.grid.q-lines tr.free td.money { font-style: italic; }
table.grid.q-lines .actions { white-space: nowrap; }

/* The cells. Bordered only on hover and focus, so a sixty-line quotation does
   not read as sixty boxes — but they are inputs, and they look like inputs the
   moment a cursor is near one. */
.cell {
  font: inherit; font-size: .88rem; color: var(--ink);
  border: 1px solid transparent; border-radius: 6px;
  padding: 5px 7px; background: transparent; width: 100%;
}
.cell:hover { border-color: var(--line); }
.cell:focus { border-color: var(--green-mid); background: var(--card); outline: none; }
.cell.wide { min-width: 220px; }
.cell.num { min-width: 92px; text-align: right; }
.cell.tiny { min-width: 64px; text-align: right; }

tr.voided { opacity: .55; }
tr.voided td { text-decoration: line-through; }
tr.voided td.actions { text-decoration: none; }

/* --- the search-as-you-type picker ---------------------------------------
   Never a <select>: the account's price list is a thousand rows, and a
   dropdown of a thousand rows is not a control. */
.picker-results {
  margin-top: 6px; max-height: 260px; overflow-y: auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card);
}
.picker-results:empty { display: none; }
.picker-row {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  border-bottom: 1px solid var(--line-soft); padding: 9px 11px; cursor: pointer; font: inherit;
}
.picker-row:last-child { border-bottom: 0; }
.picker-row:hover { background: var(--green-lite); }
.picker-row .d { display: block; font-size: .9rem; }
.picker-row .m { display: block; font-size: .78rem; color: var(--ink-faint); margin-top: 2px; }

/* --- the company logo ----------------------------------------------------- */

.logo-row { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; margin: 0 0 18px; }
.logo-well {
  flex: 0 0 auto; width: 140px; height: 90px;
  border: 1px dashed var(--line); border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  /* A chequerboard, so a PNG with a transparent background reads as
     transparent here rather than as white-on-white. */
  background-image:
    linear-gradient(45deg, var(--line-soft) 25%, transparent 25%),
    linear-gradient(-45deg, var(--line-soft) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--line-soft) 75%),
    linear-gradient(-45deg, transparent 75%, var(--line-soft) 75%);
  background-size: 14px 14px;
  background-position: 0 0, 0 7px, 7px -7px, -7px 0;
  padding: 8px;
}
.logo-well img { max-width: 100%; max-height: 100%; object-fit: contain; }
.logo-actions { flex: 1 1 260px; }
.logo-actions .field { margin-bottom: 8px; }

/* --- what's new, and what is wrong ---------------------------------------- */

.nav button .dot {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 5px; margin-left: 6px;
  border-radius: 999px; background: var(--sun); color: #4a2f05;
  font-size: .68rem; font-weight: 700; vertical-align: 1px;
}

.feed { display: grid; gap: 12px; }
.feed-item {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px;
  background: var(--card);
}
/* An update this reader has not opened. It fades the moment they do, which is
   the only signal a change log needs. */
.feed-item.fresh { border-color: var(--sun); background: var(--sun-lite); }
.feed-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.feed-head .spacer { flex: 1; }
.feed-head strong { font-weight: 650; }
.feed-body { margin-top: 7px; font-size: .92rem; color: var(--ink-soft); white-space: pre-wrap; }

/* --- the colour pickers --------------------------------------------------- */

.colour-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.colour-row input[type=color] {
  width: 56px; height: 38px; padding: 2px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--card);
}
.colour-hex {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .85rem; color: var(--ink-soft); text-transform: uppercase;
}

/* The account's own logo, beside the product's wordmark. It sits on the dark
   bar, so it is given a little air and capped in height rather than scaled to
   a box — a wordmark logo is wide and a monogram is square, and both have to
   look deliberate. */
.topbar-logo {
  height: 30px; max-width: 120px; width: auto; object-fit: contain;
  margin-right: 12px; flex: 0 0 auto;
}
@media (max-width: 520px) { .topbar-logo { max-width: 78px; height: 26px; margin-right: 9px; } }

/* --- signers -------------------------------------------------------------- */

.signer-list { display: grid; gap: 10px; }
.signer {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 12px;
}
.signer-sig {
  flex: 0 0 auto; width: 130px; height: 52px;
  display: flex; align-items: center; justify-content: center;
  border-bottom: 1px solid var(--line);
}
/* A signature is drawn ABOVE its rule on paper and it is shown that way here,
   so a white-boxed JPEG is obvious before it reaches a client's document. */
.signer-sig img { max-width: 100%; max-height: 100%; object-fit: contain; }
.signer-who { flex: 1 1 180px; }
.signer-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.signer-actions .btn { cursor: pointer; }

/* A month with nothing in it. Kept in the table rather than dropped — a gap in
   a profit and loss is information, and it is the months nobody bought
   anything that matter most. */
table.grid tr.quiet td { color: var(--ink-faint); }

/* --- buying credits ------------------------------------------------------- */

.packs { display: grid; gap: 10px; margin: 4px 0 18px; grid-template-columns: 1fr; }
@media (min-width: 620px) { .packs { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); } }
.pack {
  display: grid; gap: 2px; text-align: left; cursor: pointer; font: inherit;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--card); padding: 14px 16px; color: var(--ink);
}
.pack:hover { border-color: var(--green-mid); }
/* The chosen bundle. Only one can be on, and typing a number turns them all
   off — a form that shows a bundle selected and a different number in the box
   is a form somebody sends money against. */
.pack.on { border-color: var(--green-mid); background: var(--green-lite); }
.pack-n { font-size: 1.5rem; font-weight: 700; line-height: 1.1; }
.pack-l { font-size: .82rem; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .04em; }
.pack-p { font-weight: 650; margin-top: 4px; }
.pack-e { font-size: .82rem; color: var(--ink-faint); }

.quote {
  margin: 4px 0 14px; padding: 11px 14px; border-radius: var(--radius);
  background: var(--sun-lite); border: 1px solid #f2ddb5; color: #6b4a10;
}
.quote .faint { display: block; font-size: .85rem; margin-top: 2px; }

/* The screenshot of a transfer, in the owner's queue. Small enough to scan a
   column of them, and it opens full size. */
.proof-thumb { display: inline-block; line-height: 0; }
.proof-thumb img {
  width: 54px; height: 40px; object-fit: cover;
  border: 1px solid var(--line); border-radius: 5px;
}
.danger-text { color: var(--red); }

/* ---------- The contract editor ----------

   One screen, and it is the only one in the app that edits a whole document
   rather than a row. The layout has one job: make the SHAPE of the agreement
   legible while it is being changed — which article a clause is inside, and
   what order they are in — because that is what an installer gets wrong when
   they edit a contract in Word.

   The article number in the corner is DECORATION here. The real numbering is
   computed on the server and printed by the PDF, and this badge simply counts
   the cards; it exists so that reordering visibly does something. */
.card.article { padding-top: 14px; }
.card.article .card-head {
  display: flex; align-items: center; gap: 10px; margin-bottom: 10px;
}
.article-n {
  flex: 0 0 auto;
  min-width: 26px; height: 26px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: #fff;
  font-size: 13px; font-weight: 700;
}
.article-title {
  flex: 1 1 auto; min-width: 0;
  font-weight: 700; font-size: 1rem;
}
.row-tools { flex: 0 0 auto; display: flex; gap: 4px; }
.btn.tiny {
  min-height: 26px; padding: 0 8px; font-size: 12px; line-height: 1;
}

/* A block sits INSIDE its article, and the rule on the left is what says so —
   cheaper than a nested card, and it keeps the article scannable when it holds
   six of them. */
.block {
  border-left: 3px solid var(--border);
  padding: 8px 0 8px 12px;
  margin: 0 0 10px 6px;
}
.block:last-of-type { margin-bottom: 4px; }
.block-head {
  display: flex; align-items: center; gap: 8px; margin-bottom: 6px;
}
.block .clause-label { flex: 1 1 auto; min-width: 0; font-weight: 600; }
/* Contract clauses are PROSE and have to be proof-read as prose. Left to the
   browser these are a textarea's default monospace, which is right for code
   and wrong for the paragraph a client is going to sign. */
.block textarea, .block input, .article-title {
  width: 100%;
  font: inherit;
  font-size: .9rem;
  line-height: 1.55;
  padding: 8px 10px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: #fff;
  color: var(--text);
  resize: vertical;
}
.block textarea:focus, .block input:focus, .article-title:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}
.article-title { font-weight: 700; font-size: 1rem; }
/* The payment table is the one block with no text to edit: it is a marker
   saying where the milestones print, and it is styled as one. */
.block.sched { border-left-color: var(--accent); }
.block.sched p { margin: 0; font-size: 12px; }

.contract-preview { max-height: 70vh; overflow-y: auto; }
.contract-preview h3 {
  font-size: .95rem; margin: 18px 0 6px; padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.contract-preview p { font-size: .86rem; line-height: 1.55; margin: 0 0 8px; }
.contract-preview ul { font-size: .86rem; line-height: 1.55; margin: 0 0 8px 18px; }

@media (max-width: 640px) {
  .card.article .card-head { flex-wrap: wrap; }
  .article-title { order: 3; flex-basis: 100%; }
}

/* ---------- From the audit's recommendations ---------- */

/* The handbook, one click from every screen. Quiet: it is help, not a tab. */
.help-link {
  color: rgba(255,255,255,.78); text-decoration: none; font-size: .86rem;
  padding: 6px 10px; border-radius: 8px; margin-right: 8px;
}
.help-link:hover { color: #fff; background: rgba(255,255,255,.1); }

/* The first-run checklist: five facts, ticking themselves off. */
.setup-card { border-left: 4px solid var(--sun, #e8a33d); }
.setup-list { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }
.setup-list li { display: grid; grid-template-columns: 22px auto 1fr; gap: 8px; align-items: baseline; }
.setup-list li .tick { font-weight: 700; color: var(--text-muted); }
.setup-list li.done .tick { color: var(--accent); }
.setup-list li.done a { text-decoration: line-through; color: var(--text-muted); }
@media (max-width: 640px) { .setup-list li { grid-template-columns: 22px 1fr; } .setup-list li .faint { grid-column: 2; } }

/* A plain list of links with a date on the right, for the client page. */
ul.plain { list-style: none; margin: 0; padding: 0; }
ul.plain li { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--border); }
ul.plain li:last-child { border-bottom: 0; }

/* Money cells are text inputs so they can show a thousands separator at
   rest; right-aligned like the numbers they are. */
.cell.money-cell { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------- The business card ----------
   Free, and it has to LOOK free-but-good: the preview is the print rectangle
   (85.6 × 54 mm, ID-1) scaled, with the account's own colours. */
.free-pill {
  display: inline-block; vertical-align: middle;
  background: var(--accent); color: #fff;
  font-size: .68rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px; margin-left: 8px;
}
.free-pill.small { font-size: .58rem; padding: 2px 7px; margin-left: 5px; }
.nav button .free-pill { background: var(--sun, #e8a33d); color: #1d2320; }

/* The second wallet. Plan credits are marked wherever a figure could be
   mistaken for ordinary credits — the statement, the console, the pill. */
.plans-pill {
  display: inline-block; vertical-align: middle;
  background: #2f5d8a; color: #fff;
  font-size: .68rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px; margin-left: 8px;
}
.plans-pill.small { font-size: .58rem; padding: 2px 7px; margin-left: 5px; }
.credits-pill .pill-plans { font-weight: 400; opacity: .85; }
.stat.plans-stat { border-left: 3px solid #2f5d8a; }
.plans-row td:first-child { border-left: 3px solid #2f5d8a; }
.wallet-pick { display: grid; gap: 10px; grid-template-columns: 1fr; margin: 4px 0 16px; }
@media (min-width: 640px) { .wallet-pick { grid-template-columns: 1fr 1fr; } }
.wallet-opt {
  display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: start;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; cursor: pointer;
  background: var(--card);
}
.wallet-opt.on { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent); }
.wallet-opt input { margin-top: 3px; }
.wallet-opt .wallet-name { font-weight: 700; }
.wallet-opt .wallet-sub { grid-column: 2; font-size: .82rem; color: var(--muted); }
.wallet-pick.compact { margin-bottom: 10px; }
.plan-buy {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between;
  padding: 12px 14px; border: 1px solid #2f5d8a; border-radius: 10px; background: color-mix(in srgb, #2f5d8a 8%, var(--card));
  margin-bottom: 14px;
}
.plan-buy .plan-buy-text { flex: 1 1 320px; }
.paywall .tier { font-size: .82rem; color: #6b4c1e; background: #f6ecd9; border-radius: 8px; padding: 6px 10px; margin: 6px 0 4px; display: inline-block; }
.tier-row td:first-child { border-left: 3px solid #b8862b; }
.refer-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 6px 0 8px; }
.refer-link { flex: 1 1 320px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9rem; }
.refer-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .12em; font-size: 1.05rem; }

.bc-stage {
  display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin: 6px 0 18px;
}
@media (max-width: 760px) { .bc-stage { grid-template-columns: 1fr; } }
.bc-side .bc-label { font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 6px; }

.bc {
  position: relative; overflow: hidden;
  width: 100%; aspect-ratio: 85.6 / 54;
  border-radius: 10px; padding: 5.8% 6%; box-sizing: border-box;
  background: #fff; color: #1d2320;
  box-shadow: 0 10px 28px rgba(0,0,0,.14), 0 1px 0 rgba(0,0,0,.06);
  display: flex; flex-direction: column; justify-content: space-between;
  container-type: inline-size;
}
.bc.bold { background: var(--p); color: #fff; }
.bc .rays {
  position: absolute; right: -14%; top: -30%; width: 55%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, var(--a) 0 18%, transparent 19%),
              repeating-conic-gradient(from 0deg, var(--a) 0 4deg, transparent 4deg 12deg);
  opacity: .16; pointer-events: none;
}
.bc.bold .rays { opacity: .28; }
.bc-top { display: flex; align-items: center; gap: 3cqw; position: relative; }
.bc-logo { height: 15cqw; max-width: 32cqw; object-fit: contain; background: #fff; border-radius: 3px; padding: 1px; }
.bc-co { font-weight: 700; letter-spacing: .06em; text-transform: uppercase; font-size: 3.2cqw; color: var(--p); }
.bc.bold .bc-co { color: #fff; }
.bc-who { position: relative; }
.bc-name { font-size: 6.4cqw; font-weight: 700; line-height: 1.1; }
.bc-title { font-size: 3.6cqw; font-weight: 600; color: var(--a); margin-top: 1cqw; }
.bc-tag { font-size: 3cqw; opacity: .75; margin-top: 1.4cqw; }
.bc-lines { font-size: 3.3cqw; line-height: 1.5; position: relative; }
.bc:not(.bold)::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2.6%; background: var(--a); }

.bc.back { padding: 0; justify-content: flex-start; }
.bc-back-band { height: 17%; background: var(--p); display: flex; align-items: center; padding: 0 6%; }
.bc.bold .bc-back-band { background: var(--a); }
.bc-back-band .bc-co { color: #fff; }
.bc-back-body { display: flex; justify-content: space-between; gap: 4cqw; padding: 4% 6% 0; flex: 1; }
.bc-back-lines { font-size: 3.1cqw; line-height: 1.55; }
.bc.bold .bc-back-lines { color: #fff; }
.bc-qr { flex: 0 0 auto; width: 22cqw; aspect-ratio: 1; background: #fff; border-radius: 4px; padding: 1cqw; box-sizing: border-box; }
.bc-qr svg { width: 100%; height: 100%; display: block; }
.bc-qr-hint { font-size: 2.4cqw; color: #6a736d; text-align: center; padding-top: 30%; }
.bc-made { font-size: 2.4cqw; color: #7a827c; padding: 0 6% 4%; }
.bc.bold .bc-made { color: #dfe4e0; }

.bc-share-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.bc-share-row input { flex: 1 1 240px; min-width: 0; }
.bc-qr-big { margin-top: 14px; }
.bc-qr-big svg { width: 180px; height: 180px; border: 1px solid var(--border); border-radius: 8px; background: #fff; padding: 8px; }
label.check { display: flex; gap: 8px; align-items: center; margin-top: 10px; font-size: .92rem; }
.free-row td { background: rgba(232,163,61,.07); }

/* ---------- Electrical plans ---------- */
.load-table input, .load-table select { width: 100%; min-width: 0; font-size: .85rem; padding: 5px 6px; }
.load-table input.tiny { width: 64px; } .load-table input.num { width: 84px; }
.load-table td.r { text-align: right; font-variant-numeric: tabular-nums; }
.sheet-list { display: grid; gap: 18px; }
.sheet-preview { position: relative; background: #fff; border: 1px solid var(--border); border-radius: 6px; padding: 6px; overflow: hidden; }
.sheet-preview svg { width: 100%; height: auto; display: block; }
.sheet-preview .sheet-no { position: absolute; top: 8px; left: 8px; background: var(--accent); color: #fff; font-size: .7rem; font-weight: 700; padding: 2px 8px; border-radius: 999px; }
