/* =====================================================================
   SMB Ventures OS — shell styling
   Neutral chrome, brand color used as the accent on whatever record you
   are looking at. Four companies in one window without four color
   schemes fighting each other.
   ===================================================================== */

:root {
  --ink: #16181D;
  --ink-2: #454A54;
  --ink-3: #767C89;
  --line: #E3E6EB;
  --line-2: #EFF1F4;
  --bg: #F7F8FA;
  --panel: #FFFFFF;
  --brand: #6B7280;
  --brand-soft: #F3F4F6;
  --brand-ink: #4B5563;
  --on-brand: #FFFFFF;
  --good: #12805C;
  --good-soft: #E4F4EE;
  --warn: #A66300;
  --warn-soft: #FDF1DF;
  --bad: #C0392B;
  --bad-soft: #FCECEA;
  --radius: 10px;
  --radius-sm: 7px;
  --shadow: 0 1px 2px rgba(16, 18, 23, .05), 0 4px 14px rgba(16, 18, 23, .05);
  --font: 'Jost', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--brand-ink); }
h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -.011em; }
h1 { font-size: 21px; }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
p { margin: 0 0 10px; }

/* ---------------------------------------------------------------- app */
.app { display: flex; min-height: 100vh; }

/* -------------------------------------------------------------- rail */
.rail {
  width: 232px;
  flex: 0 0 232px;
  background: #14161B;
  color: #B9BFCB;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}
.rail-head { padding: 18px 18px 14px; border-bottom: 1px solid #24272F; }
.rail-logo { color: #fff; font-weight: 600; font-size: 15px; letter-spacing: -.01em; }
.rail-sub { font-size: 11px; color: #767C89; margin-top: 2px; letter-spacing: .04em; text-transform: uppercase; }

.rail-group { padding: 14px 10px 4px; }
.rail-group-label {
  font-size: 10px; text-transform: uppercase; letter-spacing: .09em;
  color: #5B616E; padding: 0 8px 6px; font-weight: 600;
}
.rail a.nav {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 10px; margin: 1px 0;
  border-radius: var(--radius-sm);
  color: #B9BFCB; text-decoration: none; font-size: 13.5px;
}
.rail a.nav:hover { background: #1D2027; color: #fff; }
.rail a.nav.on { background: #262A33; color: #fff; font-weight: 500; }
.rail a.nav .ico { width: 16px; text-align: center; opacity: .8; font-size: 13px; }
.rail a.nav .count {
  margin-left: auto; font-size: 11px; background: #2E323C;
  padding: 1px 6px; border-radius: 20px; color: #C9CFDA;
}
.rail a.nav .count.hot { background: var(--bad); color: #fff; }
/* A badge with no number is not a badge. Without this an empty span
   still paints its pill and reads as a stray dash next to the label. */
.rail a.nav .count:empty { display: none; }

.rail-foot { margin-top: auto; padding: 12px; border-top: 1px solid #24272F; font-size: 12px; }
.rail-foot .who { color: #fff; font-weight: 500; }
.rail-foot .build { color: #5B616E; font-size: 10.5px; margin-top: 4px; font-family: var(--mono); }

/* ------------------------------------------------------------- brand bar */
.brandbar { display: flex; gap: 4px; padding: 6px 10px 12px; flex-wrap: wrap; }
.brandchip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 9px; border-radius: 20px; cursor: pointer;
  font-size: 11.5px; border: 1px solid #2E323C; background: #1A1D23; color: #9BA2AF;
  user-select: none;
}
.brandchip:hover { border-color: #444A57; color: #E7EAEF; }
.brandchip.on { color: #fff; border-color: transparent; }
.brandchip .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* ------------------------------------------------------------- main */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 24px; background: var(--panel);
  border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 20;
}
.topbar h1 { flex: 0 0 auto; }
/* The back button sits left of the title and only appears when there is
   somewhere to go. It names its destination, because an unlabelled arrow
   makes you click it to find out where it goes. */
#back-slot { flex: 0 0 auto; }
#back-slot:empty { display: none; }
.backbtn { color: var(--ink-3); padding-left: 6px; padding-right: 9px; }
.backbtn:hover { color: var(--ink); background: var(--line-2); }
.topbar .sub { color: var(--ink-3); font-size: 12.5px; }
.topbar .spacer { flex: 1; }

.content { padding: 20px 24px 60px; flex: 1; }
.content.wide { max-width: none; }

/* ------------------------------------------------------------ demo flag */
.demobar {
  background: #2B2F38; color: #DCE0E7; font-size: 12.5px;
  padding: 7px 24px; display: flex; gap: 10px; align-items: center;
}
.demobar b { color: #fff; font-weight: 600; }

/* ------------------------------------------------------------- cards */
.grid { display: grid; gap: 14px; }
/* Grid and flex children default to min-width:auto, which means a wide
   child (a nowrap table, a long unbroken string) refuses to shrink and
   pushes the whole page sideways instead of scrolling inside its own
   card. Everything that can hold a table gets min-width:0. */
.grid > *, .stack > *, .card, .card-body, .main, .content { min-width: 0; }
.grid.c2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.card-head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 16px; border-bottom: 1px solid var(--line-2);
}
.card-head h2 { flex: 0 0 auto; }
.card-head .spacer { flex: 1; }
.card-body { padding: 16px; }
.card-body.flush { padding: 0; }

/* stat tiles */
.stat { padding: 15px 16px; }
.stat .label { font-size: 11.5px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
.stat .value { font-size: 25px; font-weight: 600; letter-spacing: -.02em; margin-top: 5px; font-variant-numeric: tabular-nums; }
.stat .note { font-size: 12px; color: var(--ink-3); margin-top: 3px; }
.stat .value.bad { color: var(--bad); }
.stat .value.good { color: var(--good); }

/* -------------------------------------------------------------- table */
table.t { width: 100%; border-collapse: collapse; font-size: 13.5px; }
table.t th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); font-weight: 600; padding: 9px 14px;
  border-bottom: 1px solid var(--line); white-space: nowrap; background: #FCFCFD;
}
table.t td { padding: 10px 14px; border-bottom: 1px solid var(--line-2); vertical-align: middle; }
table.t tbody tr:hover { background: #FBFCFD; }
table.t tbody tr.clickable { cursor: pointer; }
table.t td.num, table.t th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.t .muted { color: var(--ink-3); }

.empty { padding: 34px 16px; text-align: center; color: var(--ink-3); font-size: 13px; }
.empty .big { font-size: 15px; color: var(--ink-2); margin-bottom: 4px; }

/* --------------------------------------------------------------- bits */
.tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 20px; font-size: 11.5px; font-weight: 500;
  background: var(--brand-soft); color: var(--brand-ink); white-space: nowrap;
}
.tag .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.tag.good { background: var(--good-soft); color: var(--good); }
.tag.warn { background: var(--warn-soft); color: var(--warn); }
.tag.bad  { background: var(--bad-soft);  color: var(--bad); }
.tag.flat { background: var(--line-2); color: var(--ink-2); }

.pri { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
.pri.urgent { color: var(--bad); }
.pri.high { color: var(--warn); }
.pri.normal { color: var(--ink-3); }
.pri.low { color: var(--ink-3); opacity: .7; }

.avatar {
  width: 25px; height: 25px; border-radius: 50%; flex: 0 0 25px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 600; background: var(--line-2); color: var(--ink-2);
}

.money { font-variant-numeric: tabular-nums; }
.muted { color: var(--ink-3); }
/* Bare state colors. These were missing, so every "3 days late" the app
   printed with class="small bad" rendered in ordinary ink — the one
   place color is carrying meaning rather than decoration. */
.bad  { color: var(--bad); }
.warn { color: var(--warn); }
.good { color: var(--good); }
td.bad, td.warn { font-weight: 500; }
.small { font-size: 12px; }
.right { text-align: right; }
.row { display: flex; align-items: center; gap: 10px; }
.row.wrap { flex-wrap: wrap; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.hidden { display: none !important; }

/* ------------------------------------------------------------ controls */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--panel); color: var(--ink);
  font-family: var(--font); font-size: 13px; font-weight: 500; cursor: pointer;
  white-space: nowrap;
}
.btn:hover { background: #FAFBFC; border-color: #D3D8E0; }
.btn.primary { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
.btn.primary:hover { filter: brightness(1.08); }
.btn.ghost { border-color: transparent; background: transparent; color: var(--ink-2); }
.btn.ghost:hover { background: var(--line-2); }
.btn.sm { padding: 4px 9px; font-size: 12px; }
.btn.danger { color: var(--bad); border-color: var(--bad-soft); }
.btn:disabled { opacity: .5; cursor: not-allowed; }

input[type=text], input[type=email], input[type=password], input[type=date],
input[type=time], input[type=number], input[type=tel], select, textarea {
  width: 100%; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); font-family: var(--font); font-size: 13.5px;
  background: var(--panel); color: var(--ink);
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}
textarea { min-height: 84px; resize: vertical; line-height: 1.55; }
label.f { display: block; margin-bottom: 12px; }
label.f > span {
  display: block; font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 5px;
}
label.f .help { font-weight: 400; color: var(--ink-3); font-size: 11.5px; }
.f-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }

.search {
  padding: 7px 11px; border: 1px solid var(--line); border-radius: 20px;
  font-size: 13px; width: 250px; background: var(--panel);
}

/* ------------------------------------------------------------- kanban */
.kanban { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 12px; }
.kcol { flex: 0 0 268px; background: #F1F3F6; border-radius: var(--radius); padding: 10px; }
.kcol-head { display: flex; align-items: center; gap: 8px; padding: 2px 4px 10px; }
.kcol-head .n { font-size: 13px; font-weight: 600; }
.kcol-head .v { margin-left: auto; font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.kcard {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 10px 11px; margin-bottom: 8px;
  cursor: grab; box-shadow: 0 1px 2px rgba(16,18,23,.04);
}
.kcard:active { cursor: grabbing; }
.kcard.drag { opacity: .4; }
.kcol.over { background: #E6EAF0; outline: 2px dashed #C3CAD6; outline-offset: -4px; }
.kcard .kt { font-weight: 500; font-size: 13px; margin-bottom: 5px; }
.kcard .km { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--ink-3); }

/* -------------------------------------------------------------- modal */
.scrim {
  position: fixed; inset: 0; background: rgba(16, 18, 23, .42);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 6vh 16px; z-index: 100; overflow-y: auto;
}
.modal {
  background: var(--panel); border-radius: 12px; width: 100%; max-width: 560px;
  box-shadow: 0 20px 60px rgba(16, 18, 23, .28); overflow: hidden;
}
.modal.wide { max-width: 820px; }
.modal-head {
  display: flex; align-items: center; padding: 15px 18px;
  border-bottom: 1px solid var(--line-2);
}
.modal-head h2 { flex: 1; }
.modal-body { padding: 18px; max-height: 66vh; overflow-y: auto; }
.modal-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 13px 18px; border-top: 1px solid var(--line-2); background: #FCFCFD;
}

/* -------------------------------------------------------------- toast */
.toasts { position: fixed; right: 18px; bottom: 18px; z-index: 300; display: flex; flex-direction: column; gap: 8px; }
.toast {
  background: #1B1E24; color: #fff; padding: 11px 15px; border-radius: var(--radius-sm);
  font-size: 13px; box-shadow: 0 8px 26px rgba(0,0,0,.28); max-width: 380px;
  display: flex; gap: 9px; align-items: flex-start;
}
.toast.bad { background: #8E2A20; }
.toast.good { background: #0E6349; }
.toast .x { margin-left: auto; cursor: pointer; opacity: .6; }

/* ------------------------------------------------------------- detail */
.detail-head {
  display: flex; align-items: flex-start; gap: 14px; padding: 18px 20px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); margin-bottom: 14px;
  border-left: 4px solid var(--brand);
}
.detail-head .id-block { flex: 1; min-width: 0; }
.detail-head h1 { margin-bottom: 3px; }

.tabs {
  display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 16px;
  /* Six filter tabs do not fit on a phone. Scroll the strip rather than
     the page — scrollbar hidden, because it sits under the tab labels. */
  overflow-x: auto; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs button {
  padding: 9px 14px; border: none; background: none; cursor: pointer;
  flex: 0 0 auto; white-space: nowrap;
  font-family: var(--font); font-size: 13.5px; color: var(--ink-3);
  border-bottom: 2px solid transparent; margin-bottom: -1px; font-weight: 500;
}
.tabs button:hover { color: var(--ink); }
.tabs button.on { color: var(--brand-ink); border-bottom-color: var(--brand); }

.kv { display: grid; grid-template-columns: 128px 1fr; gap: 7px 12px; font-size: 13.5px; }
.kv dt { color: var(--ink-3); font-size: 12.5px; }
.kv dd { margin: 0; }

.timeline { position: relative; padding-left: 18px; }
.timeline::before {
  content: ''; position: absolute; left: 4px; top: 5px; bottom: 5px;
  width: 1px; background: var(--line);
}
.tl-item { position: relative; padding: 0 0 14px; font-size: 13px; }
.tl-item::before {
  content: ''; position: absolute; left: -18px; top: 5px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--panel); border: 2px solid var(--brand);
}
.tl-item .when { font-size: 11.5px; color: var(--ink-3); margin-top: 1px; }

/* checklist rows */
.check { display: flex; align-items: center; gap: 9px; padding: 8px 0; border-bottom: 1px solid var(--line-2); }
.check:last-child { border-bottom: none; }
.check input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--brand); flex: 0 0 auto; }
.check .lbl { flex: 1; }
.check.done .lbl { text-decoration: line-through; color: var(--ink-3); }

/* progress */
.bar { height: 5px; border-radius: 3px; background: var(--line-2); overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--brand); }

/* --------------------------------------------------------- responsive */
@media (max-width: 1100px) {
  .grid.c4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid.c3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Phone-only invoice cards (b0926); shown by the phone rules below. */
.inv-cards { display: none; }
@media (max-width: 860px) {
  /* The rail becomes a horizontal strip. Without an explicit width cap it
     sizes the whole column flex container to its own content and drags the
     page sideways, so both it and .app are pinned to the viewport and the
     strip scrolls inside itself. */
  .app { flex-direction: column; width: 100%; max-width: 100%; }
  .rail {
    width: 100%; max-width: 100vw; min-width: 0; flex: none; height: auto; position: static;
    flex-direction: row; overflow-x: auto; align-items: center; gap: 4px; padding: 8px;
    -webkit-overflow-scrolling: touch;
  }
  .main { min-width: 0; max-width: 100%; }
  .rail-head, .rail-foot, .rail-group-label { display: none; }
  /* The company switcher stays on a phone — picking one business is the
     main way this app is used, so it cannot be a desktop-only control. */
  .brandbar {
    display: flex; padding: 0 6px 0 0; margin-right: 6px; flex: 0 0 auto;
    border-right: 1px solid #2E323C; flex-wrap: nowrap;
  }
  .rail-group { display: flex; padding: 0; }
  .rail a.nav { white-space: nowrap; }
  .grid.c2, .grid.c3, .grid.c4 { grid-template-columns: 1fr; }
  .f-row { grid-template-columns: 1fr; }
  .content, .topbar { padding-left: 14px; padding-right: 14px; }
  /* Title and action buttons do not fit on one line on a phone, and the
     topbar is a flex row that would otherwise push the page sideways. */
  /* On a phone every horizontal run of controls wraps rather than
     pushing the page sideways — a row of folder links or action buttons
     cannot be made narrow enough to fit on one line at 400px. */
  .row { flex-wrap: wrap; }
  .detail-head { flex-wrap: wrap; }
  /* A card title plus its action button does not fit beside a long
     client name on a phone, and the header was the one flex row still
     refusing to wrap. */
  .card-head { flex-wrap: wrap; row-gap: 6px; }
  .card-head h2 { flex: 1 1 auto; min-width: 0; }
  .topbar { flex-wrap: wrap; row-gap: 8px; gap: 8px; }
  .topbar h1 { flex: 1 1 100%; }
  .topbar .sub { flex: 1 1 100%; }
  .topbar .spacer { display: none; }
  #page-actions { flex: 1 1 100%; flex-wrap: wrap; }
  .search { width: 100%; }
  .kv { grid-template-columns: 1fr; gap: 2px 0; }
  .kv dd { margin-bottom: 8px; }
  table.t { display: block; overflow-x: auto; white-space: nowrap; }
  /* Invoices on a phone: one card each, buttons in reach (b0926). */
  .inv-table { display: none; }
  .inv-cards { display: block; }
}
.inv-card {
  background: var(--panel, #fff); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 14px; margin-bottom: 10px; cursor: pointer;
}
.inv-card .btn.sm { padding: 8px 12px; font-size: 14px; }


/* =====================================================================
   PRINTABLE CODES (#/codes)
   Sized so two cards sit side by side on a sheet of paper and each one
   can be cut out and stood on a table.
   ===================================================================== */
.codegrid {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.codecard {
  border: 1px solid var(--line); border-radius: 12px; background: #fff;
  padding: 22px 18px 20px; text-align: center; break-inside: avoid;
}
.codecard svg { width: 230px; height: 230px; max-width: 100%; margin: 6px auto 12px; display: block; }
.codehead { font-size: 19px; font-weight: 650; letter-spacing: -0.01em; }
.codetag { font-size: 12.5px; color: var(--ink-2); margin: 3px 0 6px; }
.codeurl {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; letter-spacing: .01em; word-break: break-all;
}
.codesay { font-size: 12.5px; color: var(--ink-2); margin-top: 8px; line-height: 1.5; }

@media print {
  .noprint, .sidebar, .topbar, .pagehead .btn, button { display: none !important; }
  .codecard { border-color: #999; }
  .codegrid { grid-template-columns: repeat(2, 1fr); gap: 24px; }
  body { background: #fff; }
}


/* The task row opens the work it belongs to, so the cell holding the
   edit button must not also do that. */
tr.clickable td.noclick { cursor: default; }
tr.clickable td.noclick .btn { opacity: .55; }
tr.clickable:hover td.noclick .btn { opacity: 1; }

/* 24 Sep: a client record carries a lot of buttons. They wrap onto a
   second line rather than running off the right edge, where Delete and
   Fired used to disappear. */
#page-actions { flex-wrap: wrap; justify-content: flex-end; row-gap: 6px; min-width: 0; flex: 0 1 auto; }

/* The proposal editor's lines (migration 68): table cells that are
   form fields, styled like every other field in the app. */
.pe-table input:not([type=checkbox]), .pe-table textarea {
  width: 100%; font: inherit; font-size: 13.5px; padding: 7px 9px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--panel, #fff); color: var(--ink);
}
.pe-table textarea { resize: vertical; }
.pe-table td { vertical-align: top; }
.pe-table input[type=checkbox] { width: 16px; height: 16px; margin-top: 9px; accent-color: var(--brand); }

/* =====================================================================
   QUICK INVOICE (b1005)
   A line on the new-invoice form: what it is, then price and quantity
   side by side even on a phone. On the invoice page, the line table
   becomes one block per line on a phone.
   ===================================================================== */
.inv-line {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 10px 12px 2px; margin-bottom: 10px;
}
.inv-qp { display: grid; grid-template-columns: 2fr 1fr; gap: 10px; }
.inv-lines-narrow { display: none; }
.inv-ln { padding: 10px 16px; border-bottom: 1px solid var(--line-2); }
.inv-ln-top { display: flex; gap: 12px; justify-content: space-between; align-items: baseline; }
.inv-ln-top b { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.inv-ln-top .money { white-space: nowrap; font-weight: 600; }
.inv-ln-sub { display: flex; gap: 6px; align-items: center; margin-top: 2px; }
@media (max-width: 860px) {
  .inv-lines-wide { display: none; }
  .inv-lines-narrow { display: block; }
  .inv-line .f-row, .inv-qp { grid-template-columns: 2fr 1fr; }
}
