@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("../fonts/Figtree-Variable.woff2") format("woff2-variations"),
    url("../fonts/Figtree-Variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("../fonts/Figtree-Variable-ext.woff2") format("woff2-variations"),
    url("../fonts/Figtree-Variable-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --ikon-purple: #662383;
  --ikon-purple-dark: #4e1a64;
  --ikon-purple-light: #f3e9f7;
  --border: #e0e0e0;
  --text: #222;
  --text-muted: #777;
  --bg: #f7f6f8;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: "Figtree", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--text);
  background: var(--bg);
}

/* ---------- Login ---------- */

.login-body {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background: linear-gradient(135deg, var(--ikon-purple), var(--ikon-purple-dark));
}

.login-card {
  background: #fff;
  border-radius: 12px;
  padding: 40px;
  width: 360px;
  text-align: center;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}

.login-logo {
  display: block;
  width: 180px;
  max-width: 80%;
  height: auto;
  margin: 0 auto 4px;
}

.login-subtitle {
  margin: 4px 0 16px;
  color: var(--text-muted);
}

.login-note {
  font-size: 12px;
  color: var(--text-muted);
  background: var(--ikon-purple-light);
  border-radius: 6px;
  padding: 8px;
}

.login-staff-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 16px;
}

.login-staff-btn {
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  font-size: 14px;
}

.login-staff-btn:hover {
  background: var(--ikon-purple-light);
  border-color: var(--ikon-purple);
}

/* Google sign-in button. Follows Google's identity guidelines: white button,
   full-colour "G", the exact wording "Sign in with Google". */
.login-google-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  box-sizing: border-box;
  padding: 11px 16px;
  margin: 8px 0 16px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  color: #3c4043;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.login-google-btn:hover {
  background: var(--ikon-purple-light);
  border-color: var(--ikon-purple);
}

.login-google-mark {
  width: 18px;
  height: 18px;
  flex: none;
}

.login-error {
  margin: 0 0 16px;
  padding: 10px 12px;
  border: 1px solid #f0b4b4;
  border-radius: 6px;
  background: #fdf0f0;
  color: #8a1f1f;
  font-size: 13px;
  text-align: left;
}

/* ---------- App shell ---------- */

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

.sidebar {
  width: 220px;
  transition: width 0.18s ease;
  background: var(--ikon-purple);
  color: #fff;
  flex-shrink: 0;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.sidebar-footer {
  margin-top: auto;
  padding: 16px 20px;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.7);
  line-height: 1.5;
}

.sidebar-version {
  font-weight: 600;
  color: #fff;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 20px;
}

/* Sits in the purple so it survives the collapse — on the rail it is the only
   way back. */
.sidebar-collapse {
  flex: none;
  margin-left: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 6px;
  color: #fff;
  cursor: pointer;
}
.sidebar-collapse:hover {
  background: rgba(255, 255, 255, 0.22);
  border-color: rgba(255, 255, 255, 0.5);
}
.sidebar-collapse-icon {
  width: 16px;
  height: 16px;
  transition: transform 0.18s ease;
}

.sidebar-logo {
  display: block;
  width: 100%;
  max-width: 160px;
  height: auto;
}

.sidebar-mark {
  display: none;
  width: 32px;
  height: 32px;
}

.sidebar-nav {
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px;
  color: rgba(255, 255, 255, 0.85);
  text-decoration: none;
  font-size: 14px;
  border-left: 3px solid transparent;
}
.nav-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  opacity: 0.9;
}

.nav-item:hover {
  background: rgba(255, 255, 255, 0.08);
}

.nav-item.active {
  background: rgba(255, 255, 255, 0.12);
  border-left-color: #fff;
  color: #fff;
  font-weight: 600;
}

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

.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 24px;
  background: #fff;
  border-bottom: 1px solid var(--border);
}

.page-title {
  margin: 0;
  font-size: 18px;
  flex: 1;
}

.sidebar-toggle {
  display: none;
  background: none;
  border: none;
  font-size: 20px;
  cursor: pointer;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.current-user {
  font-size: 13px;
  color: var(--text-muted);
}

.content {
  padding: 24px;
  flex: 1;
}

/* ---------- Buttons ---------- */

.btn {
  border: 1px solid var(--ikon-purple);
  background: var(--ikon-purple);
  color: #fff;
  padding: 8px 14px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
}

.btn:hover {
  background: var(--ikon-purple-dark);
}

/* Greyed-out disabled buttons (e.g. Send / Sync to QuickBooks in review mode). */
.btn:disabled,
.btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  filter: grayscale(60%);
}
.btn:disabled:hover,
.btn[disabled]:hover {
  background: var(--ikon-purple);
}
.btn-secondary:disabled:hover,
.btn-secondary[disabled]:hover {
  background: #fff;
}

.btn-text {
  background: none;
  border: none;
  color: var(--ikon-purple);
  font-size: 13px;
  cursor: pointer;
  padding: 0;
  /* A button centres its text by default, which only shows once the label
     wraps — a long client name in a register column then sat centred while
     every unwrapped name beside it was left-aligned. */
  text-align: left;
}

.btn-secondary {
  background: #fff;
  color: var(--ikon-purple);
}

/* ---------- Module sections ---------- */

.module-section {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 24px;
}

/* The gap below a section only earns its place between two of them. On the
   last one it is dead space under the card, and on a register that is height
   it could have given to the rows — fitTableScroll() hands back whatever the
   page overflows by, so this margin was coming straight off the table. */
.module-section:last-child {
  margin-bottom: 0;
}

.module-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

.module-section-header h2 {
  margin: 0;
  font-size: 16px;
}

/* ---------- Filter pills ---------- */

.filter-pills {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
}

.filter-bar {
  display: flex;
  gap: 16px;
  margin-bottom: 16px;
  flex-wrap: wrap;
  align-items: flex-end;
}

.filter-bar .form-row {
  flex: 0 0 auto;
  min-width: 170px;
  margin-bottom: 0;
}

.filter-bar .form-row.search {
  flex: 0 0 340px;
  max-width: 100%;
}

.filter-pill {
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: #fff;
  font-size: 13px;
  cursor: pointer;
}

.filter-pill.active {
  background: var(--ikon-purple);
  border-color: var(--ikon-purple);
  color: #fff;
}

/* ---------- Date-range filter (Harvest style) ---------- */

.daterange {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.daterange-label {
  font-size: 20px;
  font-weight: 700;
}

.daterange-group {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background: #fff;
}

.daterange-group .dr-arrow {
  border: none;
  background: #fff;
  padding: 7px 14px;
  cursor: pointer;
  color: #333;
  font-size: 15px;
  line-height: 1;
}

.daterange-group .dr-arrow:hover:not(:disabled) {
  background: #f3f3f3;
}

.daterange-group .dr-arrow:disabled {
  color: #ccc;
  cursor: not-allowed;
}

.daterange-group .dr-select {
  border: none;
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  background: #fff;
  padding: 7px 14px;
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  color: #333;
  min-width: 130px;
  text-align: center;
  text-align-last: center;
}

.daterange-custom {
  display: inline-flex;
  gap: 8px;
}

.daterange-custom input[type="date"] {
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
}

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

.summary-cards {
  display: flex;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.summary-card {
  flex: 1;
  min-width: 160px;
  background: #fff;
  border: 1px solid var(--border);
  border-top: 3px solid var(--border);
  border-radius: 8px;
  padding: 16px;
}

.summary-card .label {
  font-size: 12px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.summary-card .value {
  font-size: 22px;
  font-weight: 700;
  margin-top: 4px;
}

.summary-card .sub {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* Project summary split into a row of tiles per phase code + a total row. */
.summary-rows {
  margin-bottom: 20px;
}

.summary-row {
  display: flex;
  align-items: stretch;
  gap: 16px;
}

/* One equal column per tile, however many there are (3 for Mid and below, 5
   with Costs + Profit/Loss) — a flex row wraps Profit/Loss onto its own line
   once the phase label takes its 128px. */
.summary-row .summary-cards {
  flex: 1;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 12px;
  margin-bottom: 12px;
}

.summary-row .summary-card {
  min-width: 0;
  padding: 12px 14px;
}

.summary-row .summary-card .value {
  font-size: 19px;
}

/* Efficiency tile: same tier-coloured chip as the register, sized up to sit at
   the tile's value size. */
.summary-row .summary-card .value .eff-chip {
  font-size: 17px;
  padding: 1px 11px;
  min-width: 0;
}

.summary-row-label {
  flex: 0 0 128px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  font-size: 15px;
  font-weight: 700;
  color: var(--ikon-purple);
  padding-right: 4px;
}

.summary-row-label span {
  display: block;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-top: 2px;
}

/* Project-level costs that belong to no phase — a sub-consultant fee, or
   expenses. A single line rather than another row of tiles: the tiles carry
   Ikon's own billable work and cost, and a second set of them competed with
   the figures they exist to show. */
.summary-line {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 7px 0;
  font-size: 13px;
  border-top: 1px dashed var(--border);
  margin-bottom: 12px;
}

/* Same 128px label column as .summary-row, so the label lines up with DD / CA
   and Total Summary. */
.summary-line .summary-line-label {
  flex: 0 0 128px;
  padding-right: 4px;
  font-weight: 700;
  color: var(--ikon-purple);
}

.summary-line .summary-line-label span {
  display: block;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0;
  margin-top: 1px;
}

/* Mirrors .summary-row .summary-cards exactly — same column count, same gap —
   so the figure lands under the Costs tile rather than floating at the far
   right of the panel. */
.summary-line-cols {
  flex: 1;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 12px;
  align-items: center;
}

/* Sized to match the tile figures it sits under, but left regular weight —
   the tiles are bold because they are the project's own numbers, and these
   are not. */
.summary-line-value {
  font-size: 19px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  padding: 0 14px;
}

/* A line that is NOT part of the total above it — expenses. Set apart so it is
   never read as another component of the project's cost. */
.summary-line.is-excluded {
  border-top-style: solid;
  margin-top: 4px;
  opacity: 0.75;
}

/* The total row reads as the sum of the rows above it. */
.summary-row.is-total {
  border-top: 2px solid var(--border);
  padding-top: 14px;
}

.summary-row.is-total .summary-card {
  background: var(--ikon-purple-light);
}

@media (max-width: 1100px) {
  .summary-row {
    display: block;
  }
  .summary-row .summary-cards {
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  }
  .summary-row-label {
    flex-direction: row;
    align-items: baseline;
    justify-content: flex-start; /* base rule centres it vertically in the tall row */
    gap: 8px;
    margin-bottom: 8px;
  }
  .summary-row-label span {
    margin-top: 0;
  }
}

.summary-card.inprogress {
  border-top-color: #3a4f9a;
}
.summary-card.won {
  border-top-color: #2e7d46;
}
.summary-card.lost {
  border-top-color: #c0392b;
}

/* ---------- Dashboard ---------- */
.eff-quarters {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}
@media (max-width: 900px) {
  .eff-quarters { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .eff-quarters { grid-template-columns: 1fr; }
}
.eff-quarter {
  padding: 14px 16px;
}
.eff-q-label {
  font-size: 15px;
  font-weight: 700;
  color: var(--ikon-purple);
  text-align: center;
}
.eff-q-donut {
  display: flex;
  justify-content: center;
  margin: 8px 0 6px;
}
.eff-q-money {
  font-size: 11px;
  color: var(--text-muted);
  margin: 0 0 8px;
  text-align: center;
}
.eff-months {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.eff-month {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 13px;
  padding: 3px 0;
  border-bottom: 1px solid #f3f3f5;
}
.eff-month:last-child { border-bottom: none; }
.eff-month-name {
  width: 34px;
  color: var(--text-muted);
}
.eff-month-val {
  font-weight: 600;
  min-width: 42px;
  text-align: center;
  color: #333;
  padding: 1px 8px;
  border-radius: 4px;
}
/* Tier-coloured efficiency chip (project register + anywhere efficiency shows) */
.eff-chip {
  display: inline-block;
  min-width: 44px;
  text-align: center;
  font-weight: 600;
  color: #333;
  padding: 2px 10px;
  border-radius: 4px;
}
.eff-month-money {
  margin-left: auto;
  font-size: 11px;
  color: var(--text-muted);
}
.eff-year-summary {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  margin-top: 16px;
  padding: 12px 24px;
  background: var(--ikon-purple-light);
  border-radius: 8px;
}
.eff-year-donut { flex: 0 0 auto; }
.eff-year-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.eff-year-label {
  font-weight: 700;
  color: var(--ikon-purple);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-size: 16px;
}
.eff-year-money {
  font-size: 13px;
  color: var(--text-muted);
}
/* Efficiency matrix (target tiers) — sits at the right of the year banner */
.eff-matrix-wrap { margin-left: auto; }
.eff-matrix-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  margin-bottom: 4px;
  text-align: center;
}
.eff-matrix {
  border-collapse: collapse;
  font-size: 13px;
  background: #fff;
  border-radius: 6px;
  overflow: hidden;
}
/* White spacer row below the last (purple) tile, mirroring the header band on top */
.eff-matrix tr.em-foot td { height: 8px; padding: 0; background: #fff; }
.eff-matrix td {
  padding: 3px 12px;
  white-space: nowrap;
}
.eff-matrix .em-name { text-align: left; color: var(--text); }
.eff-matrix .em-pct { text-align: center; font-weight: 600; color: #333; }
.eff-matrix .em-rate { text-align: right; color: var(--text); }
.eff-matrix tr.is-target td { font-weight: 700; }
.eff-matrix tr.em-head td {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  font-weight: 600;
  padding-bottom: 2px;
}
.eff-matrix tr.em-head td:nth-child(2) { text-align: center; }
.eff-matrix tr.em-head td:nth-child(3) { text-align: right; }
/* Donut centre labels sit on white; keep the % readable in the tinted year banner */
.eff-year-summary .donut svg text { font-weight: 700; }
.dash-two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
@media (max-width: 900px) {
  .dash-two-col { grid-template-columns: 1fr; }
}
.dash-two-col .module-section { margin-bottom: 0; }

/* Profit/loss + efficiency text colours */
.pos { color: #2e7d46; }
.neg { color: #c0392b; }
.dash-table strong.won,
.data-table strong.won { color: #2e7d46; }
.dash-table strong.lost,
.data-table strong.lost { color: #c0392b; }

/* Budget-used mini bar */
.mini-bar {
  display: inline-block;
  vertical-align: middle;
  width: 84px;
  height: 7px;
  background: #ececef;
  border-radius: 4px;
  overflow: hidden;
}
.mini-bar-fill {
  display: block;
  height: 100%;
  background: var(--ikon-purple);
  border-radius: 4px;
}
.mini-bar-fill.won { background: #2e7d46; }
.mini-bar-fill.lost { background: #c0392b; }
/* Over an ESTIMATE (a CA phase, or a project with no fixed fee) — worth a look,
   but not the loss that going over a fee is. */
.mini-bar-fill.warn { background: #e67e22; }
.mini-bar-pct {
  font-size: 12px;
  color: var(--text-muted);
  margin-left: 8px;
  vertical-align: middle;
}
.mini-bar-pct.lost { color: #c0392b; }
.mini-bar-pct.warn { color: #d35400; }

/* ---------- Tabs ---------- */

.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;
}

.tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 16px;
  font-size: 14px;
  color: var(--text-muted);
  cursor: pointer;
  margin-bottom: -1px;
}

.tab:hover {
  color: var(--ikon-purple);
}

.tab.active {
  color: var(--ikon-purple);
  border-bottom-color: var(--ikon-purple);
  font-weight: 600;
}

/* ---------- Tables ---------- */

table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.text-muted {
  color: var(--text-muted);
}

.nowrap {
  white-space: nowrap;
}

th .sort-caret {
  font-size: 9px;
  color: var(--ikon-purple);
  margin-left: 4px;
}

.status-select {
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  font-family: inherit;
  background: #fff;
}

.clickable-row {
  cursor: pointer;
}

/* ---------- Expenses ---------- */

/* An expense that's been Invoiced or Reimbursed reads as done. */
tr.exp-status-done > td {
  background: #eafaf0;
}

.status-select.exp-status-done {
  border-color: #2e9e5b;
  color: #1f7a44;
  font-weight: 600;
}

/* GST / PST / Other tax / Billable to client all on one row. */
.exp-checks {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  align-items: center;
}

.exp-inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: inherit;
}

.exp-inline input {
  width: auto;
  margin: 0;
}

/* Live tax breakout under the amount field in the entry modal. */
.exp-breakout {
  margin: 4px 0 12px;
  padding: 10px 12px;
  background: var(--ikon-purple-light);
  border-radius: 8px;
  font-size: 13px;
}

.exp-breakout:empty {
  display: none;
}

.exp-breakout-row {
  display: flex;
  justify-content: space-between;
  padding: 2px 0;
  color: var(--text-muted);
}

.exp-breakout-row.total {
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px solid rgba(0, 0, 0, 0.12);
  color: var(--text);
  font-weight: 700;
}

.exp-breakout-billable {
  margin-top: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ikon-purple);
}

/* ---------- Project dashboard ---------- */

.health-banner {
  border-radius: 8px;
  padding: 14px 16px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  border-left: 4px solid var(--text-muted);
  background: #f7f6f8;
}

.health-banner .health-text {
  font-size: 14px;
}

.health-banner.ok {
  background: #e7f4ea;
  border-left-color: #2e7d46;
}

.health-banner.danger {
  background: #fcebea;
  border-left-color: #c0392b;
}

/* Not an error — the week is simply not reachable yet, and there is a clear
   thing to do about it. */
.health-banner.warn {
  background: #fdf4e3;
  border-left-color: #e08a1e;
}

.health-banner.neutral {
  background: var(--ikon-purple-light);
  border-left-color: var(--ikon-purple);
}

.health-util {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  color: var(--text-muted);
  min-width: 240px;
  flex: 1;
  max-width: 360px;
}

.health-util .bar-track {
  flex: 1;
}

.phase-prog {
  margin-bottom: 12px;
}

.phase-prog:last-child {
  margin-bottom: 0;
}

.phase-prog-head {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  margin-bottom: 4px;
}

/* ---------- Project analysis charts ---------- */

.chart-grid {
  display: grid;
  grid-template-columns: 3fr 1fr;
  gap: 16px;
  margin-bottom: 12px;
}

.chart-card {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px;
}

.chart-card h3 {
  margin: 0 0 14px;
  font-size: 14px;
}

.chart-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.chart-card-head h3 {
  margin: 0;
}

.efficiency-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.chart-card h3.efficiency-title {
  font-size: 28px;
  line-height: 1.1;
  text-align: center;
}

.efficiency-card .donut {
  width: 100%;
  display: flex;
  justify-content: center;
}

.efficiency-card .donut svg {
  width: 150px;
  height: auto;
}

.chart-legend {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
  font-size: 12px;
  color: var(--text-muted);
}

.chart-legend span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.chart-legend i {
  width: 12px;
  height: 12px;
  border-radius: 2px;
  display: inline-block;
}

.chart-pt {
  cursor: pointer;
}

.chart-tooltip {
  position: absolute;
  background: #222;
  color: #fff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 10;
}

.bar-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

.bar-label {
  width: 150px;
  font-size: 12px;
  color: var(--text-muted);
  flex-shrink: 0;
}

.bar-track {
  flex: 1;
  background: #f0f0f0;
  border-radius: 4px;
  height: 14px;
  overflow: hidden;
}

.bar-track.sm {
  height: 8px;
  width: 80px;
  flex: 0 0 80px;
}

.bar-fill {
  height: 100%;
  border-radius: 4px;
  transition: width 0.3s ease;
}

.bar-val {
  width: 90px;
  text-align: right;
  font-size: 12px;
  flex-shrink: 0;
}

.donut-row {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}

.ratio-note {
  font-size: 12px;
  color: var(--text-muted);
  text-align: center;
  margin-top: 12px;
}

.pct-cell {
  display: flex;
  align-items: center;
  gap: 8px;
}

.expand-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--ikon-purple);
  font-size: 10px;
  padding: 2px 4px;
}

.phase-period {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.phase-period-nav {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Match the Time Tracking nav button styling. */
.phase-period select {
  padding: 6px 10px;
  font-size: 12px;
  border: 1px solid var(--ikon-purple);
  border-radius: 6px;
  background: #fff;
  color: var(--ikon-purple);
  font-family: inherit;
  font-weight: 500;
  cursor: pointer;
}

.phase-period-label {
  min-width: 120px;
  text-align: center;
  font-weight: 600;
  font-size: 13px;
}

.phase-period input[type="date"] {
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
}

.staff-detail > td {
  background: #faf8fb;
  border-bottom: 1px solid #efe9f2;
  font-size: 12px;
  padding-top: 6px;
  padding-bottom: 6px;
}

.staff-detail:hover > td {
  background: #faf8fb;
}

.staff-name {
  padding-left: 24px;
  color: var(--text-muted);
}

/* Expanded phase block. The left accent ties it visually to the project row
   above it, so a long list of expanded projects still reads as groups rather
   than one undifferentiated wall of rows. */
.proj-detail > td {
  background: #faf8fb;
}
/* The accent goes on the CONTENT cell only. The "No phases" row has two cells —
   a narrow spacer under the expand arrow, then the message — so styling every
   td drew the bar twice.
   
   Excludes the phase rows: those carry a cell per project column, where
   :last-child is the P/L Margin cell at the far right and the accent belongs on
   the phase code at the left (see tr.proj-phase-row below). */
.proj-detail:not(.proj-phase-row) > td:last-child {
  border-left: 3px solid var(--ikon-purple);
  padding-left: 14px;
}

/* Every project row gets a rule above it, and the row of an expanded project is
   tinted and bolded, so where one project ends and the next begins is obvious
   while scrolling. */
#proj-tbody tr[data-project-row] > td {
  border-top: 2px solid #e4dcea;
}
#proj-tbody tr[data-project-row].is-expanded > td {
  background: #f3eef7;
  font-weight: 600;
}

/* A project's phases, as rows of the register itself. They share the project
   row's columns, which is what makes their figures line up under the headings
   — a nested table sized its own columns and never could.

   Set apart by the purple rule down the left and a lighter ground, so the
   register still reads as a list of projects rather than a flat list of rows. */
tr.proj-phase-row > td {
  font-size: 12px;
  color: var(--text-muted);
}

tr.proj-phase-row > td:nth-child(2) {
  border-left: 3px solid var(--ikon-purple);
  font-weight: 600;
  color: var(--ikon-purple);
}

/* The figures stay readable — only the labels recede. */
tr.proj-phase-row > td.text-right {
  color: var(--text);
}

tr.proj-phase-row:hover > td {
  background: #f4ecf7;
}

/* The phase name is the one cell that can run long; let it ellipsis rather
   than widening the column the project names share. */
tr.proj-phase-row > td:nth-child(3) {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 768px) {
  .chart-grid {
    grid-template-columns: 1fr;
  }
}

.detail-back {
  margin-bottom: 12px;
}

.pos {
  color: #2e7d46;
}
.neg {
  color: #c0392b;
}

td .btn-text + .btn-text {
  margin-left: 10px;
}

table.data-table th,
table.data-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}

table.data-table th {
  color: var(--text-muted);
  font-weight: 600;
  cursor: pointer;
  user-select: none;
}

/* Scrollable dashboard table — shows ~15 rows, scroll on hover for the rest */
.dash-scroll {
  max-height: 750px; /* ~15 rows */
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.dash-scroll table.data-table {
  margin: 0;
}
.dash-scroll table.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--ikon-purple-light);
}
.dash-table tbody tr[data-project],
.dash-table tbody tr[data-opp] {
  cursor: pointer;
}
/* Column totals row (e.g. By Division). */
.dash-table tfoot .totals-row td {
  font-weight: 700;
  border-top: 2px solid var(--border);
  background: #faf9fc;
}
/* Sortable table headers */
.sortable-table th.th-sort {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
/* A header long enough to distort the table breaks over two lines instead of
   forcing its column as wide as its title.

   The column is PINNED at 135px, not merely capped or floored. `white-space:
   normal` only permits a wrap, it does not force one: on a wide screen the
   auto table layout hands the column all the room it asks for — 313px on a
   1980px viewport — and the title sits on one line again, which is the whole
   problem this is meant to solve. Fixing the width makes the wrap happen at
   every screen size.

   135px specifically: it is the width that breaks the label as "Invoiced Less"
   / "Sub-Consultant". At 140px and above it breaks mid-hyphen instead
   ("Invoiced Less Sub-" / "Consultant"), and below ~130px it goes to three
   lines. */
.sortable-table th.th-sort.th-wrap {
  white-space: normal;
  width: 135px;
  min-width: 135px;
  max-width: 135px;
  line-height: 1.25;
}
.sortable-table th.th-sort:hover {
  background: var(--ikon-purple-light);
}
.sortable-table th .sort-arrow {
  opacity: 0.5;
  font-size: 10px;
  margin-left: 3px;
}
.sortable-table th.sorted .sort-arrow {
  opacity: 1;
}
/* Per-cell delete on the timesheet — clears one entry without removing the
   whole phase row. Sits immediately left of the description pencil (the cell is
   only 30px tall, so stacking them would overlap). */
.ts-cell-del {
  position: absolute;
  top: 50%;
  right: 21px;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  padding: 0;
  border: none;
  border-radius: 3px;
  background: transparent;
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.6;
}

.ts-cell-del:hover {
  opacity: 1;
  background: #c0392b;
  color: #fff;
}

.ts-cell-del[hidden] {
  display: none;
}

/* Leave room for both buttons so a 2-digit entry can't slide underneath them. */
.ts-cell-input.has {
  padding-right: 38px;
  padding-left: 6px;
}

/* Post / Posted control beside a month in the Company Efficiency band. */
.eff-post-btn {
  margin-left: 6px;
  padding: 1px 8px;
  border: 1px solid var(--ikon-purple);
  border-radius: 999px;
  background: #fff;
  color: var(--ikon-purple);
  font-family: inherit;
  font-size: 10px;
  font-weight: 600;
  line-height: 16px;
  cursor: pointer;
  white-space: nowrap;
}
.eff-post-btn:hover:not(:disabled) {
  background: var(--ikon-purple);
  color: #fff;
}
.eff-post-btn:disabled {
  border-color: var(--border);
  color: var(--text-muted);
  cursor: not-allowed;
}
/* Already posted — reads as a state, not a call to action. */
.eff-post-btn.is-posted {
  border-color: var(--border);
  background: var(--ikon-purple-light);
  color: var(--ikon-purple);
}

/* Division filter beside a dashboard table heading. */
.dash-filter {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.dash-filter label {
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
}
.dash-filter .ss {
  min-width: 170px;
}

/* Drill-through cell on the Referral Analytics leaderboard: a count you open to
   reveal the records behind it, each of which jumps to that record. */
.drill {
  position: relative;
  display: inline-block;
}

.drill > summary {
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  color: var(--ikon-purple);
  font-weight: 600;
  white-space: nowrap;
  padding: 2px 0;
}
.drill > summary::-webkit-details-marker {
  display: none;
}
.drill > summary::after {
  content: " ▾";
  font-size: 10px;
}
.drill[open] > summary::after {
  content: " ▴";
}

.drill-list {
  position: absolute;
  z-index: 50;
  top: calc(100% + 4px);
  left: 0;
  min-width: 320px;
  max-width: 460px;
  max-height: 300px;
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.16);
  padding: 4px;
}

.drill-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 6px;
  padding: 7px 9px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.drill-item:hover {
  background: var(--ikon-purple-light);
}

.drill-item-id {
  font-weight: 600;
  white-space: nowrap;
}
.drill-item-name {
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

/* Tick-box option rows in a multi-select dropdown. The row is the click
   target, so the box itself must not swallow the click. */
.ss-opt-check {
  display: flex;
  align-items: center;
  gap: 9px;
}
.ss-opt-check input[type="checkbox"] {
  width: 15px;
  height: 15px;
  margin: 0;
  flex: 0 0 auto;
  pointer-events: none;
  accent-color: var(--ikon-purple);
}

/* Export Statement dialog: checkbox on the same line as its label. */
.stmt-check {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 4px;
  font-size: 14px;
  cursor: pointer;
}
.stmt-check input {
  width: 16px;
  height: 16px;
  margin: 0;
  flex: 0 0 auto;
}

.opening-balance-note {
  font-size: 13px;
  background: var(--ikon-purple-light);
  border-radius: 6px;
  padding: 9px 14px;
  margin: 0 0 18px;
}

/* A register that scrolls its own rows, keeping the column headers in place
   rather than letting them run off the top of the page. Used by the Projects,
   Opportunities, Clients and Referral Sources registers.

   fitTableScroll() in app.js sets the real max-height from the box's measured
   position, so it ends at the bottom of the window whatever each register
   stacks above its table — summary cards, a date range, a filter bar. Three
   registers previously meant three hand-tuned calc() guesses, and the one for
   Referral Sources was short enough to waste half the screen.

   The value below is only what applies before that runs, and the floor keeps
   the box usable on a window too short for the calc to give a sensible
   answer. */
.table-scroll {
  max-height: calc(100vh - 280px);
  min-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.table-scroll table.data-table {
  margin: 0;
}
.table-scroll table.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--ikon-purple-light);
}

table.data-table tbody tr:hover {
  background: var(--ikon-purple-light);
}

/* Opportunity row shading by status (In Progress stays white) */
table.data-table tbody tr.opp-won td { background: #e7f4ea; }
table.data-table tbody tr.opp-lost td { background: #fbe9e7; }
table.data-table tbody tr.opp-won:hover td { background: #d9edde; }
table.data-table tbody tr.opp-lost:hover td { background: #f6ddd9; }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
}

.badge-low {
  background: #eef3ee;
  color: #3a7a3a;
}

.badge-mid {
  background: #eef0f8;
  color: #3a4f9a;
}

.badge-high {
  background: var(--ikon-purple-light);
  color: var(--ikon-purple);
}

.badge-admin {
  background: var(--ikon-purple);
  color: #fff;
}

.badge-inactive {
  background: #f2f2f2;
  color: var(--text-muted);
}

.badge-inprogress {
  background: #eef0f8;
  color: #3a4f9a;
}

.badge-won {
  background: #e7f4ea;
  color: #2e7d46;
}

.badge-lost {
  background: #fcebea;
  color: #c0392b;
}

.text-right {
  text-align: right !important;
}

.text-center {
  text-align: center !important;
}

.cell-input {
  width: 80px;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 4px;
}

.cell-textarea {
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: inherit;
  font-size: 13px;
  resize: vertical;
  white-space: pre-wrap;
  word-break: break-word;
  vertical-align: top;
}

/* ---------- Modal ---------- */

#toast-wrap {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}

.toast {
  background: #222;
  color: #fff;
  padding: 10px 18px;
  border-radius: 6px;
  font-size: 14px;
  max-width: 90vw;
  text-align: center;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
}

.modal {
  background: #fff;
  border-radius: 8px;
  padding: 24px;
  width: 380px;
  max-width: 90vw;
}

.modal h3 {
  margin-top: 0;
}

.modal-body {
  max-height: 65vh;
  overflow-y: auto;
}

.form-row {
  margin-bottom: 12px;
}

.form-row label {
  display: block;
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.form-row input,
.form-row select,
.form-row textarea {
  width: 100%;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
  font-family: inherit;
}

.form-row textarea {
  resize: vertical;
}

/* Two-column modal body. The create/convert forms carry enough fields that a
   single column ran off the bottom of the screen and had to be scrolled to be
   filled in — spreading them sideways keeps the whole form in view. Rows that
   need the full width (notes, the delete panel) opt out with .form-row-full. */
.modal-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 20px;
  align-items: start;
}
.modal-grid > .form-row-full {
  grid-column: 1 / -1;
}

/* Below the width the two columns need, fall back to one. */
@media (max-width: 700px) {
  .modal-grid {
    grid-template-columns: 1fr;
  }
}

.form-row.two-col {
  display: flex;
  gap: 12px;
}

.form-row.two-col > div {
  flex: 1;
}

/* Project number with its division suffix fixed on the end, like an input
   add-on: the number is typed, the suffix follows the Division field. */
.pn-field {
  display: flex;
  align-items: stretch;
}
.form-row .pn-field input {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.pn-suffix {
  display: flex;
  align-items: center;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-left: none;
  border-radius: 0 6px 6px 0;
  background: #f4f2f6;
  color: var(--text-muted);
  font-size: 14px;
  white-space: nowrap;
}

.inline-select {
  display: flex;
  gap: 8px;
  align-items: center;
}

.inline-select select {
  flex: 1;
}
.inline-select .ss {
  flex: 1;
  min-width: 0;
}

/* Inline .ss dropdowns in filter bars get a sensible fixed width (the trigger
   is width:100% of this). */
.filter-bar .ss {
  width: 190px;
}

/* .ss styled to sit seamlessly inside the date-range pill, replacing the old
   native <select> without doubling borders. */
.daterange-group .ss {
  display: inline-flex;
}
.daterange-group .ss-trigger {
  border: none;
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  border-radius: 0;
  min-width: 130px;
  justify-content: center;
  gap: 6px;
  padding: 7px 14px;
  font-size: 13px;
}
.daterange-group .ss-trigger:hover {
  border-color: var(--border);
}

/* ---------- Searchable select (combobox) ---------- */
.ss {
  position: relative;
}
.ss-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 12px;
  border: 1px solid var(--border, #d9d9e3);
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  font-size: 14px;
  text-align: left;
}
.ss-trigger:hover,
.ss.open .ss-trigger {
  border-color: var(--ikon-purple, #5b3f8c);
}
.ss-value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ss-placeholder {
  color: #9aa0a6;
}
.ss-caret {
  color: #9aa0a6;
  font-size: 11px;
  flex-shrink: 0;
}
/* Floating popover over the modal — positioned in JS (fixed) so the modal's
   own scroll/overflow can't clip it. Grey box with the search bar on top. */
.ss-panel {
  position: fixed;
  z-index: 3000;
  background: #f2f2f5;
  border: 1px solid var(--border, #d9d9e3);
  border-radius: 8px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.18);
  padding: 8px;
}
.ss-search {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border, #d9d9e3);
  border-radius: 6px;
  font-size: 13px;
  margin-bottom: 8px;
  box-sizing: border-box;
  background: #fff;
}
.ss-list {
  max-height: 240px;
  overflow-y: auto;
}
.ss-opt {
  padding: 7px 10px;
  border-radius: 5px;
  cursor: pointer;
  font-size: 14px;
}
.ss-opt:hover {
  background: var(--ikon-purple-light, #f0ecf7);
}
.ss-opt.selected {
  background: var(--ikon-purple-light, #f0ecf7);
  font-weight: 600;
}
.ss-opt.ss-opt-disabled {
  color: var(--text-muted, #9aa0a6);
  cursor: not-allowed;
  opacity: 0.55;
}
.ss-opt.ss-opt-disabled:hover {
  background: none;
}
.ss-empty {
  padding: 10px;
  color: var(--text-muted, #6b6a7a);
  font-size: 13px;
  text-align: center;
}
.client-status-inline {
  padding: 4px 8px;
  font-size: 13px;
  font-weight: 600;
  border: 1px solid var(--border, #d9d9e3);
  border-radius: 5px;
}
.client-status-inline.status-active {
  background: #d9ead3;
  border-color: #b3d3a5;
  color: #2e5a1c;
}
.client-status-inline.status-inactive {
  background: #f4cccc;
  border-color: #e2a8a8;
  color: #8a1c1c;
}

.btn-sm {
  padding: 6px 10px;
  font-size: 12px;
  white-space: nowrap;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 20px;
}

/* ---------- Time tracking ---------- */

.ts-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.ts-nav {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
/* Reporting-period .ss dropdown sitting between the purple Prev / Next buttons. */
.ts-nav .ss {
  width: 180px;
}
/* Batch-action .ss dropdown in the invoicing toolbar. */
.batch-bar .ss {
  width: 230px;
}
/* Position dropdown inside a draft invoice hourly row. */
.inv-pos-cell .ss {
  width: 170px;
}

/* QuickBooks Online connection bar (Admin, above the invoice register). */
.qbo-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  margin-bottom: 14px;
  font-size: 13px;
}
.qbo-bar .qbo-text {
  flex: 1;
}
.qbo-bar .qbo-env {
  color: var(--text-muted);
  text-transform: capitalize;
}
.qbo-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
  background: #c0392b;
}
.qbo-bar.connected .qbo-dot {
  background: #2e9e5b;
}
.qbo-bar.disconnected .qbo-dot {
  background: #d9a021;
}
.qbo-bar.not-configured {
  color: var(--text-muted);
}

/* Amount input with a leading $ prefix. */
.money-input {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}
.money-input .money-prefix {
  display: flex;
  align-items: center;
  padding: 0 10px;
  background: #f2f2f5;
  color: var(--text-muted);
  border-right: 1px solid var(--border);
  font-size: 14px;
}
.money-input input {
  border: none !important;
  border-radius: 0 !important;
  flex: 1;
  min-width: 0;
}
.money-input input:focus {
  outline: none;
}

/* Invoice document + activity-history side panel. */
.invoice-layout {
  display: flex;
  gap: 20px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.invoice-layout .invoice-doc {
  flex: 1 1 620px;
  min-width: 0;
  margin: 0;
}
.invoice-activity {
  flex: 0 0 600px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px 18px;
}
.invoice-activity h3 {
  margin: 0 0 10px;
  font-size: 15px;
}
.act-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.act-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 9px 0;
  border-bottom: 1px solid #f1f0f4;
  white-space: nowrap;
}
.act-item:last-child {
  border-bottom: none;
}
.act-icon {
  flex-shrink: 0;
  text-align: center;
  font-size: 13px;
  line-height: 1.4;
}
.act-label {
  font-weight: 600;
  font-size: 13px;
  flex-shrink: 0;
}
.act-detail {
  font-size: 12px;
  color: var(--text-muted);
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.act-meta {
  font-size: 11px;
  color: #9aa0a6;
  flex-shrink: 0;
  margin-left: auto;
  padding-left: 12px;
}
.act-item.act-viewed .act-label {
  color: var(--ikon-purple);
}
.act-item.act-payment .act-label {
  color: #1f7a44;
}
.act-empty {
  color: var(--text-muted);
  font-size: 13px;
  padding: 6px 0;
}
@media (max-width: 1400px) {
  .invoice-activity {
    flex-basis: 100%;
  }
}

/* Staff-review lockdown banner (REVIEW_MODE) shown atop the Invoicing module. */
.review-banner {
  background: #fff4e5;
  border: 1px solid #f0c27a;
  color: #8a5a00;
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 13px;
  line-height: 1.5;
  margin-bottom: 14px;
}

/* Per-invoice QuickBooks sync status under the invoice actions. */
.qbo-status {
  font-size: 12px;
  margin: -6px 0 14px;
}
.qbo-status.ok {
  color: #1f7a44;
}
.qbo-status.err {
  color: #c0392b;
}
.qbo-status.muted {
  color: var(--text-muted);
}

.ts-range {
  font-weight: 600;
  margin-left: 8px;
}

.ts-viewtoggle {
  display: flex;
  gap: 4px;
}

.ts-hint,
.ts-range {
  font-size: 13px;
}

.ts-hint {
  background: var(--ikon-purple-light);
  color: var(--ikon-purple);
  padding: 8px 12px;
  border-radius: 6px;
  margin-bottom: 12px;
}

.timesheet-wrap {
  overflow-x: auto;
}

.phase-pick-list {
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
}

.phase-pick-item {
  padding: 8px 12px;
  cursor: pointer;
  font-size: 13px;
  border-bottom: 1px solid #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.phase-pick-item:last-child {
  border-bottom: none;
}

.phase-pick-item:hover {
  background: var(--ikon-purple-light);
}

.phase-pick-item.selected {
  background: var(--ikon-purple);
  color: #fff;
}

.phase-pick-item.disabled {
  color: #aaa;
  cursor: not-allowed;
  background: #f7f7f7;
}

.phase-pick-item.disabled:hover {
  background: #f7f7f7;
}

.phase-pick-item .pill {
  font-size: 10px;
  border: 1px solid #ccc;
  border-radius: 999px;
  padding: 1px 7px;
  color: #999;
  white-space: nowrap;
}

.phase-pick-empty {
  padding: 10px 12px;
  color: var(--text-muted);
  font-size: 13px;
}

/* "Add Row" dropdown on My Timesheet (replaced the old pop-up dialog). Built on
   the .ss combobox look used by the client picker, but with its own absolutely
   positioned panel — it isn't inside a modal, so it doesn't need the fixed
   positioning that .ss-panel uses to escape one. */
.ts-addrow {
  display: flex;
  align-items: center;
  gap: 12px;
}
/* Its display:flex would otherwise beat the hidden attribute on a read-only week. */
.ts-addrow[hidden] {
  display: none;
}

.ts-addrow-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}

.ts-addrow-ss {
  min-width: 360px;
}

.ts-addrow-trigger {
  padding: 12px 16px;
  font-size: 15px;
  border-radius: 8px;
}

.ts-addrow-panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 6px);
  right: 0;
  width: 560px;
  max-width: 85vw;
}

/* Ten rows before it scrolls (rows run ~42px). */
.ts-addrow-list {
  max-height: 420px;
}

.ts-addrow-list .phase-pick-item {
  cursor: default;
  background: #fff;
  border-radius: 6px;
  border-bottom: 1px solid #eceaf2;
  font-size: 14px;
}

.ts-addrow-list .phase-pick-item:hover {
  background: var(--ikon-purple-light);
}

.ts-addrow-list .phase-pick-empty {
  background: #fff;
}

/* "Show N more" footer — a real button, so it reads as clickable. */
.phase-pick-more {
  display: block;
  width: 100%;
  padding: 10px 12px;
  margin-top: 2px;
  background: #fff;
  border: 1px dashed var(--border);
  border-radius: 6px;
  color: var(--ikon-purple);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.phase-pick-more:hover {
  background: var(--ikon-purple-light);
  border-style: solid;
}

.phase-pick-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

.ts-add-btn {
  padding: 4px 14px;
}

@media (max-width: 900px) {
  .ts-addrow {
    width: 100%;
  }
  .ts-addrow-ss {
    flex: 1;
    min-width: 0;
  }
  .ts-addrow-panel {
    width: 100%;
  }
}

table.timesheet th.ts-phase,
table.timesheet td.ts-phase {
  min-width: 220px;
}

table.timesheet th {
  text-align: center;
}

/* Sortable timesheet headers (Project Phase on My Timesheet; Staff + Project
   Phase on Team). Left-aligned like the cells beneath them. */
table.timesheet th.sortable {
  cursor: pointer;
  text-align: left;
  user-select: none;
}
table.timesheet th.sortable:hover {
  color: var(--ikon-purple);
}

.ts-daynum {
  font-weight: 400;
  color: var(--text-muted);
  font-size: 11px;
}

.ts-total {
  font-weight: 700;
}
/* Whole totals row (incl. its label) reads bold. */
.timesheet tfoot td {
  font-weight: 700;
}
/* Reporting-period selector in the timesheet toolbar. */
.ts-period {
  display: flex;
  align-items: center;
  gap: 8px;
}
.ts-period select,
.ts-period input[type="date"] {
  padding: 6px 10px;
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: 6px;
}

.ts-remove {
  border: 1px solid var(--border);
  background: #fff;
  border-radius: 6px;
  width: 26px;
  height: 26px;
  cursor: pointer;
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1;
}

.ts-remove:hover {
  border-color: #c0392b;
  color: #c0392b;
}

.today-col {
  background: var(--ikon-purple-light);
}

/* Hours are typed straight into the grid cell (Harvest-style). */
.ts-cell-input {
  width: 100%;
  min-width: 52px;
  height: 30px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: #fff;
  font-size: 13px;
  padding: 4px;
  text-align: center;
  font-family: inherit;
}

.ts-cell-input:hover {
  border-color: var(--ikon-purple);
}

.ts-cell-input:focus {
  outline: none;
  border-color: var(--ikon-purple);
  box-shadow: 0 0 0 2px var(--ikon-purple-light);
}

.ts-cell-input.has {
  background: var(--ikon-purple-light);
  font-weight: 600;
  /* Leave room for the description pencil. */
  padding-right: 20px;
}

.ts-cell-input.locked {
  cursor: not-allowed;
  opacity: 0.7;
}

/* Note popover anchored under the cell just filled in. */
.ts-note-pop {
  position: fixed;
  z-index: 400;
  width: 380px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
  padding: 14px;
  text-align: left;
  /* Never taller than the window it is positioned inside — on a short screen
     the panel would otherwise run past the bottom edge whichever side of the
     cell it was placed. */
  max-height: calc(100vh - 16px);
  overflow-y: auto;
}

.ts-note-label {
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 6px;
}

.ts-note-req {
  font-weight: 400;
  color: var(--text-muted);
}

.ts-note-text {
  width: 100%;
  min-height: 110px;
  font-family: inherit;
  font-size: 13px;
  line-height: 1.45;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px;
  resize: vertical;
}

.ts-note-text:focus {
  outline: none;
  border-color: var(--ikon-purple);
  box-shadow: 0 0 0 2px var(--ikon-purple-light);
}

/* Save attempted with an empty description. */
.ts-note-pop.invalid .ts-note-text {
  border-color: #c0392b;
  box-shadow: 0 0 0 2px rgba(192, 57, 43, 0.12);
}

.ts-note-pop.invalid .ts-note-req {
  color: #c0392b;
}

/* Reason the save was refused — hidden until there is one to give. */
.ts-note-err {
  display: none;
  margin-top: 6px;
  font-size: 12px;
  color: #c0392b;
}

.ts-note-pop.invalid .ts-note-err {
  display: block;
}

.ts-note-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
}

/* Marks a repeat line of a phase already on the sheet. */
.ts-line-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 10px;
  background: var(--ikon-purple-light);
  color: var(--ikon-purple);
  font-size: 11px;
  font-weight: 700;
  vertical-align: middle;
}

.pill-line {
  background: var(--ikon-purple-light);
  color: var(--ikon-purple);
}

/* Cell holds the hours input plus its description pencil. */
.ts-cell-wrap {
  position: relative;
  display: block;
}

.ts-note-btn {
  position: absolute;
  top: 50%;
  right: 3px;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  height: 17px;
  padding: 0;
  border: none;
  border-radius: 3px;
  background: transparent;
  color: var(--ikon-purple);
  cursor: pointer;
  opacity: 0.65;
}

.ts-note-btn:hover {
  opacity: 1;
  background: #fff;
}

.ts-note-btn[hidden] {
  display: none;
}

/* Period dropdown sitting between the Prev / Next buttons — styled to match
   them so the three read as one control group. */
.ts-period-select {
  padding: 6px 28px 6px 12px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  border: 1px solid var(--ikon-purple);
  border-radius: 6px;
  background-color: var(--ikon-purple);
  color: #fff;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 12px 12px;
}

.ts-period-select:hover {
  filter: brightness(1.08);
}

.ts-period-select option {
  background: #fff;
  color: var(--text);
}

table.timesheet tbody tr:hover {
  background: transparent;
}

/* ---------- Invoicing ---------- */

.inv-project-list {
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px;
}

.inv-project-list .inv-project-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 8px;
  font-size: 13px;
  border-radius: 4px;
  cursor: pointer;
  line-height: 1.2;
}

.inv-project-list .inv-project-item input[type="checkbox"] {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin: 0;
}

.inv-project-list .inv-project-item:hover {
  background: var(--ikon-purple-light);
}

.inv-proj-count {
  font-size: 12px;
  margin-top: 6px;
}

.batch-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.batch-bar select {
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: inherit;
  font-size: 13px;
  background: #fff;
}

.batch-bar .text-muted {
  font-size: 12px;
}

.invoice-totals {
  margin: 18px 0 0 auto;
  max-width: 320px;
}

.invoice-totals > div {
  display: flex;
  justify-content: space-between;
  padding: 6px 0;
  font-size: 14px;
}

.invoice-totals .grand {
  border-top: 2px solid var(--ikon-purple);
  font-size: 16px;
}

.invoice-actions,
.detail-back {
  margin-bottom: 12px;
}

.invoice-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.invoice-doc {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 32px;
  max-width: 820px;
}

.invoice-doc-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 20px;
  border-bottom: 2px solid var(--ikon-purple);
  padding-bottom: 16px;
}

.invoice-meta {
  text-align: right;
  font-size: 13px;
}

.invoice-doc-title {
  font-size: 20px;
  font-weight: 700;
  color: var(--ikon-purple);
  margin-bottom: 4px;
}

.invoice-client {
  margin: 16px 0;
}

.invoice-doc h4 {
  margin: 20px 0 8px;
  font-size: 14px;
  color: var(--ikon-purple);
}

table.inv-doc-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

table.inv-doc-table th,
table.inv-doc-table td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid #eee;
}

table.inv-doc-table th {
  color: var(--text-muted);
  font-weight: 600;
}

table.inv-doc-table.fixed {
  table-layout: fixed;
}

table.inv-doc-table.fixed td.wrap {
  white-space: normal;
  word-break: break-word;
  vertical-align: top;
}

/* Invoice meta table + parties (matches the Harvest layout). */
.inv-meta-table {
  margin-left: auto;
  border-collapse: collapse;
  font-size: 13px;
}

.inv-meta-table td {
  padding: 2px 0 2px 16px;
  text-align: right;
}

.inv-meta-table td:first-child {
  color: var(--text-muted);
}

.invoice-parties {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  margin: 16px 0 8px;
}

/* Hourly phase heading — same look as the "Fixed Fee Phases" headings,
   left-aligned with the date column text below. */
.inv-phase-heading {
  font-weight: 400;
  font-size: 13px;
  color: var(--text);
  margin: 14px 0 5px;
  padding-left: 10px;
}

/* Pay Now (left) + Account Summary banner (right) on one row. */
.invoice-pay-account {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-top: 20px;
  margin-bottom: 24px;
}

.invoice-pay-account .invoice-paynow {
  margin: 0;
}

.invoice-pay-account .invoice-paynow .btn {
  padding: 14px 32px;
  font-size: 16px;
}

.invoice-paynow-note {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-muted);
}

/* Invoice preview pop-up iframe. */
.inv-preview {
  margin: -4px 0;
}
.inv-preview-frame {
  width: 100%;
  height: 64vh;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
}

.invoice-account-block {
  width: 540px;
  max-width: 100%;
}

.account-summary-title {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  font-weight: 600;
  margin-bottom: 6px;
}

.invoice-account-h {
  display: flex;
  gap: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 18px;
}

.invoice-account-h > div {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.invoice-account-h > div span {
  white-space: nowrap;
}

.invoice-account-h > div span {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.invoice-account-h > div strong {
  font-size: 16px;
}

.invoice-account-h .grand strong {
  color: var(--ikon-purple);
}

.invoice-memo-custom {
  margin-top: 18px;
  padding: 12px 14px;
  background: var(--bg);
  border-radius: 8px;
  font-size: 13px;
}

.invoice-memo-custom p {
  margin: 4px 0 0;
  white-space: pre-wrap;
}

.invoice-paynow {
  margin: 20px 0;
}

.invoice-memo {
  font-size: 12px;
  color: var(--text-muted);
  border-top: 1px solid var(--border);
  padding-top: 12px;
}

/* Send Invoice modal */
.send-note {
  font-size: 12px;
  border-radius: 6px;
  padding: 10px 12px;
  margin: 12px 0 6px;
  line-height: 1.4;
}
.send-note.ok { background: #eef7f0; border: 1px solid #cce7d4; color: #2f6b43; }
.send-note.warn { background: #fdf6e7; border: 1px solid #f0e0b8; color: #8a6d1f; }
.send-attach { font-size: 12px; color: var(--text-muted); margin: 4px 0; }
.send-preview {
  width: 100%;
  height: 360px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  margin-top: 4px;
}

@media print {
  .sidebar,
  .topbar,
  .invoice-actions,
  .detail-back,
  .invoice-paynow,
  /* Editor-only reference data — must never appear on a printed invoice. */
  .source-time-ref {
    display: none !important;
  }
  .invoice-doc {
    border: none;
    padding: 0;
    max-width: none;
  }
  .content {
    padding: 0;
  }
}

/* ---------- Draft editor: original timesheet reference ----------
   Deliberately styled as a muted, secondary panel: it is working reference for
   whoever is editing, not part of the invoice. Visibly distinct from the
   editable tables above so the two are never confused. */

.source-time-ref {
  border: 1px dashed var(--border, #d5d8de);
  border-radius: 8px;
  padding: 12px 14px;
  background: var(--surface-muted, #fafbfc);
}

.source-time-ref > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
}

.source-time-ref table {
  margin-top: 6px;
  font-size: 12px;
}

/* Entries that were removed from the invoice during editing. */
.source-time-ref tr.dropped td {
  opacity: 0.55;
  text-decoration: line-through;
}

.source-time-ref tr.dropped td:last-child {
  text-decoration: none;
}

/* ---------- Collapsed sidebar (icon rail) ----------
   Desktop only. Below 768px the sidebar is off-canvas and .sidebar-collapsed
   is ignored — the toggle slides it instead of narrowing it. */

@media (min-width: 769px) {
  .app-shell.sidebar-collapsed .sidebar {
    width: 64px;
  }

  /* 64px leaves no room for the mark and the arrow side by side, so they
     stack — the arrow stays at the top, which is where it was before the
     collapse. */
  .app-shell.sidebar-collapsed .sidebar-brand {
    flex-direction: column;
    gap: 10px;
    padding: 16px 8px;
  }
  .app-shell.sidebar-collapsed .sidebar-logo {
    display: none;
  }
  .app-shell.sidebar-collapsed .sidebar-mark {
    display: block;
  }
  .app-shell.sidebar-collapsed .sidebar-collapse {
    margin-left: 0;
  }
  /* Points the other way once collapsed: it now expands. */
  .app-shell.sidebar-collapsed .sidebar-collapse-icon {
    transform: rotate(180deg);
  }

  /* Labels go; the icons stay centred. The 3px right padding balances the
     active item's 3px left border so icons don't shift when selected. */
  .app-shell.sidebar-collapsed .nav-item {
    justify-content: center;
    gap: 0;
    padding: 12px 3px 12px 0;
  }
  .app-shell.sidebar-collapsed .nav-item span,
  .app-shell.sidebar-collapsed .sidebar-improve span,
  .app-shell.sidebar-collapsed .sidebar-copyright {
    display: none;
  }

  .app-shell.sidebar-collapsed .sidebar-footer {
    padding: 16px 8px;
    text-align: center;
  }
  .app-shell.sidebar-collapsed .sidebar-improve {
    justify-content: center;
    gap: 0;
    margin: 0 8px 12px;
    padding: 8px 0;
  }
}

/* ---------- Mobile ---------- */

@media (max-width: 768px) {
  .sidebar-toggle {
    display: block;
  }

  /* The mobile sidebar slides fully off-canvas rather than narrowing, so the
     collapse arrow has nothing to do — the hamburger is the control here. */
  .sidebar-collapse {
    display: none;
  }

  .sidebar {
    position: fixed;
    left: -220px;
    top: 0;
    bottom: 0;
    z-index: 40;
    transition: left 0.2s ease;
  }

  .sidebar.open {
    left: 0;
  }

  .content {
    padding: 14px;
  }

  table.data-table {
    font-size: 12px;
  }
}

/* ---------- Invoice CC list (client form) ---------- */

.cc-list { display: flex; flex-direction: column; gap: 6px; }
.cc-list:not(:empty) { margin-bottom: 8px; }

.cc-row { display: flex; align-items: center; gap: 6px; }
.cc-row .cc-email { flex: 1 1 auto; min-width: 0; }

.cc-remove {
  flex: none;
  width: 28px;
  height: 28px;
  line-height: 1;
  font-size: 18px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  color: var(--text-muted);
  cursor: pointer;
}
.cc-remove:hover { border-color: #c0392b; color: #c0392b; }

.field-hint { font-weight: 400; color: var(--text-muted); font-size: 12px; }

/* ---------- Destructive actions, set apart from the rest of a form ---------- */

.danger-zone {
  margin-top: 18px;
  padding: 12px 14px;
  border: 1px solid #f0c9c9;
  border-radius: 6px;
  background: #fdf4f4;
  font-size: 13px;
}

.danger-zone-label {
  font-weight: 600;
  color: #8a1f1f;
  margin-bottom: 4px;
}

.btn-danger {
  background: #c0392b;
  border-color: #c0392b;
  color: #fff;
}
.btn-danger:hover { background: #a53224; border-color: #a53224; }

/* ---------- QuickBooks sync dot (invoice register) ----------
   Deliberately NOT .qbo-dot: that class belongs to the connection bar above
   and defaults to red, which would have made every row look like an error. */

.qbo-sync-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  vertical-align: middle;
  /* An inset ring as well as a fill, so the state is still distinguishable
     printed in greyscale rather than carried by colour alone. */
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18) inset;
}

.qbo-sync-dot.qbo-ok      { background: #27ae60; }
.qbo-sync-dot.qbo-pending { background: #e08a1e; }
.qbo-sync-dot.qbo-error   { background: #c0392b; }
.qbo-sync-dot.qbo-none    { background: transparent; box-shadow: 0 0 0 1px var(--border) inset; }

/* ---------- Batch send: recipient review ---------- */

.send-recipients { font-size: 13px; }
.send-recipients td { vertical-align: top; }
.send-recipients td:last-child { width: 34px; }

/* A row that cannot be sent. Marked with text as well as colour — "the one in
   red" is not something to rely on when the consequence is an unsent invoice. */
.send-row-blocked { background: #fdf4f4; }
.send-no-email { color: #8a1f1f; }

/* ---------- Submit Improvement (sidebar footer) ---------- */

.sidebar-improve {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 12px 12px;
  padding: 8px 10px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 6px;
  color: rgba(255, 255, 255, 0.9);
  font-size: 13px;
  text-decoration: none;
}
.sidebar-improve:hover {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.5);
  color: #fff;
}
.sidebar-improve .nav-icon { width: 16px; height: 16px; flex: none; }

/* ---------- Improvements register ---------- */

/* The description is the content of the row, so it gets the slack; every other
   column is a label or a date and stays on one line. */
.imp-desc-cell {
  min-width: 280px;
  white-space: pre-wrap;
  word-break: break-word;
}

/* Closed entries stay in the register — they are the record of what was done —
   but recede so the open ones read first. */
tr.imp-done td {
  opacity: 0.62;
}

.imp-meta { font-size: 12px; }

/* Sits at the row's right-hand end, away from the status dropdown — deleting
   and marking complete should not be neighbours. */
.imp-remove { margin-left: auto; }

.section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

/* Pre-cutover billed percentage on an imported fixed phase. Muted: it is
   context for the % complete above it, not a value anyone edits. */
.opening-billed {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
  white-space: nowrap;
  cursor: help;
}

/* A section header carrying BOTH a date range and a filter picker. .daterange
   has a 16px bottom margin for when it sits alone above a table; inside a
   centred flex row that margin makes its box taller than the picker's, so the
   two sit off-centre from each other. Drop it here only. */
.section-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.section-controls .daterange {
  margin-bottom: 0;
}


/* ---------- Client dashboard: inline field editing ---------- */

/* Each field saves on its own, so every row carries its own control rather
   than the whole record being pushed through one dialog. Two columns, because
   these are short fields and a single column of nine made the panel taller
   than the screen. */
.cd-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 12px 20px;
  margin-top: 4px;
}

.cd-field label {
  display: block;
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.cd-edit {
  display: flex;
  gap: 8px;
  align-items: flex-start;
}

.cd-edit input,
.cd-edit textarea {
  flex: 1;
  min-width: 0;
}

/* Holds its width while the label cycles Update -> Saving… -> Saved, so the
   field beside it does not jump as it saves. */
.cd-edit button {
  flex: none;
  min-width: 84px;
}

/* The CC list spans the field grid: it is a list of rows, not another
   single-line field, so it sits below rather than inside the two columns. */
.cd-field-cc {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.cd-field-cc .cc-list {
  max-width: 420px;
}

.cd-cc-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
}

/* The list saves as a unit, so its Update sits with the Add button rather than
   against any one row. */
.cd-cc-actions #cd-cc-save {
  margin-left: 4px;
}

/* ---------- Timesheet pins ---------- */

/* Sits before the phase name, quiet until used — an unpinned row should not
   look like it is carrying a control. */
.ts-pin {
  background: none;
  border: none;
  padding: 0 6px 0 0;
  cursor: pointer;
  line-height: 1;
  color: var(--text-muted);
  opacity: 0.45;
  /* The glyph is an inline SVG, so the button has to align it rather than sit
     it on the text baseline. */
  display: inline-flex;
  vertical-align: middle;
}

.ts-pin:hover {
  opacity: 1;
  color: var(--ikon-purple);
}

.ts-pin.is-pinned {
  opacity: 1;
  color: var(--ikon-purple);
}

/* Pinned rows are held at the top whichever way the column is sorted, so they
   get a tint to explain why they are not where the sort would put them. */
tr.ts-row-pinned > td {
  background: #fffaf0;
}

/* Staff picker on My Timesheet — sits between the heading and Add Row. */
.ts-staffpick {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: 16px;
}

.ts-staffpick label {
  font-size: 12px;
  color: var(--text-muted);
}

.ts-staffpick .ss {
  min-width: 210px;
}

/* ---------- Team week view: a person, and their projects under them ---------- */

tr.ts-team-staff > td {
  font-weight: 600;
}

/* Indented and tinted so the breakdown reads as belonging to the person above
   it, rather than as more people in the list. */
tr.ts-team-phase > td {
  background: #faf8fb;
  font-weight: 400;
  color: var(--text-muted);
}

tr.ts-team-phase > td:first-child {
  padding-left: 34px;
  border-left: 3px solid var(--ikon-purple);
}

/* The hours stay full strength — they are the figures being read. */
tr.ts-team-phase > td.text-center,
tr.ts-team-phase > td.ts-total {
  color: var(--text);
}

/* Read-only description: the text as written, wrapping like the textarea it
   replaces. */
.ts-note-readonly {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-muted, #fafbfc);
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 220px;
  overflow-y: auto;
}

/* Retainer tag in the invoice register — smaller than a status badge, since it
   is a qualifier on the number rather than a state of its own. */
.inv-retainer-tag {
  font-size: 10px;
  padding: 1px 6px;
  margin-left: 6px;
  vertical-align: middle;
}

/* ---------- Vacation Calendar ---------- */
.vc-year {
  font-weight: 700;
  font-size: 16px;
  min-width: 48px;
  text-align: center;
}
.vc-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  margin-bottom: 12px;
  font-size: 12px;
}
.vc-chip-label {
  margin-right: 10px;
  color: var(--text-muted);
}
.vc-legend-note {
  color: var(--text-muted);
  margin-left: auto;
}
.vc-chip {
  display: inline-block;
  min-width: 22px;
  padding: 1px 4px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 700;
  text-align: center;
}
.vc-sticky {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
  /* Bleed over the content padding so months scroll out of sight beneath it. */
  margin: -24px -24px 12px;
  padding: 16px 24px 4px;
  border-bottom: 1px solid var(--border);
}
.vc-sticky .ts-toolbar {
  margin-bottom: 10px;
}
.vc-month {
  padding: 0;
  overflow: hidden;
  margin-bottom: 6px;
}
.vc-month-head {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 14px;
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  text-align: left;
}
.vc-month-head:hover {
  background: var(--ikon-purple-light);
}
.vc-caret {
  color: var(--ikon-purple);
  width: 12px;
}
.vc-month-name {
  font-weight: 700;
  font-size: 15px;
}
.vc-month-body {
  border-top: 1px solid var(--border);
}
.vc-month-body[hidden] {
  display: none;
}
.vc-scroll {
  overflow-x: auto;
}
.vc-grid {
  border-collapse: collapse;
  font-size: 12px;
  width: 100%;
}
.vc-grid th,
.vc-grid td {
  border: 1px solid var(--border);
  padding: 0;
  text-align: center;
}
.vc-grid .vc-name {
  position: sticky;
  left: 0;
  z-index: 1;
  background: #fff;
  min-width: 150px;
  padding: 4px 10px;
  text-align: left;
  font-weight: 600;
  white-space: nowrap;
}
.vc-grid tr.vc-me .vc-name {
  color: var(--ikon-purple);
}
.vc-grid .vc-d {
  min-width: 26px;
  padding: 3px 0;
  font-weight: 600;
  line-height: 1.2;
}
.vc-grid .vc-d span {
  display: block;
  font-size: 10px;
  font-weight: 400;
  color: var(--text-muted);
}
.vc-grid .vc-d.we {
  background: #f0eff1;
}
.vc-grid .vc-d.stat {
  background: #efe3f5;
  color: var(--ikon-purple);
}
.vc-grid .today {
  box-shadow: inset 0 0 0 2px var(--ikon-purple);
}
.vc-c {
  height: 26px;
  font-weight: 700;
  font-size: 11px;
}
.vc-c.edit {
  cursor: pointer;
}
.vc-c.edit:hover {
  outline: 2px solid var(--ikon-purple);
  outline-offset: -2px;
}
.vc-grid .vc-tally {
  min-width: 48px;
  padding: 4px 6px;
  font-weight: 600;
  background: #faf8fb;
}
.vc-grid thead .vc-tally {
  font-size: 11px;
  color: var(--text-muted);
}
/* One colour per code, shared by cells, chips and the legend. */
.vc-V { background: #e3f4e4; color: #2e7d32; }
.vc-U { background: #fff1d6; color: #9a5b00; }
.vc-ST { background: #efe3f5; color: var(--ikon-purple); }
.vc-SI { background: #fbe4e1; color: #b3261e; }
.vc-R { background: #e2edf9; color: #1f5fa8; }
.vc-H { background: linear-gradient(135deg, #dff2ef 50%, #fff 50%); color: #00695c; }
.vc-c.vc-WE { background: #f0eff1; }
/* Before someone's start date, or after their last day: not theirs, and
   counted as nothing. Greyed out, and not clickable. */
.vc-c.vc-PRE,
.vc-c.vc-POST { background: repeating-linear-gradient(45deg, #dddce0, #dddce0 4px, #efeef1 4px, #efeef1 8px); }
.vc-name.vc-out { color: var(--text-muted); font-weight: 400; }
/* A weekend or moved stat that will be worked: a plain working day, with a
   small mark so it doesn't read as an ordinary weekday. */
.vc-c.vc-worked {
  background: #fff;
  background-image: radial-gradient(circle at 50% 50%, var(--ikon-purple) 2px, transparent 2.5px);
}
.vc-c.vc-linked.vc-ST {
  box-shadow: inset 0 -3px 0 var(--ikon-purple);
}
.vc-menu {
  position: absolute;
  z-index: 1000;
  min-width: 220px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.14);
  padding: 6px;
}
.vc-menu-title {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  padding: 4px 8px 6px;
}
.vc-menu button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 8px;
  border: 0;
  background: none;
  border-radius: 5px;
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.vc-menu button:hover {
  background: var(--ikon-purple-light);
}
.vc-st-table td {
  padding: 4px 6px;
  vertical-align: middle;
}
.vc-st-table input[type="text"] {
  width: 100%;
  min-width: 220px;
}
.vc-st-actions {
  white-space: nowrap;
  text-align: right;
}
.vc-calc {
  font-size: 11px;
  font-weight: 700;
  color: #9a5b00;
  background: #fff1d6;
  padding: 1px 6px;
  border-radius: 4px;
}
.vc-import-table td {
  padding: 4px 8px;
  font-size: 13px;
}
.vc-import-warn {
  color: #9a5b00;
}
.vc-move-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.vc-move-opt {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

/* ---------- Revenue Forecast ---------- */

.fc-group {
  margin-top: 22px;
}

/* The group's title on the left, its one action on the right. */
.fc-group-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 8px;
}

/* Generate sits above Select all — you pick, then you raise. */
.fc-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}

/* The group's totals, in the columns they total. It sits in the table HEAD,
   beneath the column titles, so the two read as one block and the totals stay
   attached to the headings they belong to. */
table.data-table thead tr.fc-summary-row td {
  background: var(--ikon-purple-light);
  font-weight: 600;
  border-top: 1px solid rgba(91, 63, 140, 0.18);
  padding: 8px 10px;
  /* Locked beneath the column titles, which are sticky at 0. The offset is
     their measured height — see stickSummaryRows() — because how far down it
     belongs depends on how the headings wrapped. */
  position: sticky;
  top: var(--fc-head-h, 38px);
  z-index: 1;
}

/* Where a line has got to, at a glance — the Opportunities register's idiom,
   applied to td so it beats zebra striping.
     red    pushed to next month
     amber  a draft exists, not yet with the client
     green  gone to the client */

/* The excluded row stays readable — the decision to leave it out is part of
   the meeting's record, so it is tinted rather than dimmed away. */
table.data-table tbody tr.fc-excluded td:not(:last-child):not(:nth-last-child(2)) {
  opacity: 0.7;
}

/* Fixed layout so the colgroup widths are honoured and the three sections
   line up with one another. The min-width keeps them legible on a narrow
   screen; the table-scroll around them takes over from there. */
table.data-table.fc-table {
  table-layout: fixed;
  /* Wide enough that the Name column, which takes whatever the fixed columns
     leave, still has room to be a name. Below this the wrapper scrolls. */
  min-width: 1240px;
}

table.data-table.fc-table td {
  overflow-wrap: anywhere;
}

/* Headings wrap between words, never inside one — "Generate Draft" was
   breaking after "Generat". */
table.data-table.fc-table th.fc-nowrap-head {
  overflow-wrap: normal;
  word-break: keep-all;
}

/* What a new hourly project will bill: a retainer, or the hours already on the
   clock. Stacked, because both are worth seeing at once. */
/* The two options are right-aligned as a block, but LEFT-aligned within it, so
   the boxes line up with each other rather than with the ends of two labels of
   different lengths. */
.fc-mode-opts {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  text-align: left;
  /* Exactly as wide as the Claim % box on the rows around it (70px, set inline
     on .fc-claim), so the ticks start where that box starts and the column
     reads down one edge. "Billable Hours" is longer than that and runs on past
     it into the cell's padding; the table's min-width keeps that clear of the
     Invoice Forecast figure beside it. */
  width: 70px;
}

.fc-mode-opt {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  white-space: nowrap;
  cursor: pointer;
}

/* The browser's default left margin would sit the box 4px in from that edge. */
.fc-mode-opt input {
  margin-left: 0;
}

/* A project with several phases: the project reads as the row, its phases sit
   beneath it. Indented and lighter, so the eye can skip them when scanning
   down the month and drop into them when checking one project. */
table.data-table tbody tr.fc-parent td {
  font-weight: 600;
}

table.data-table tbody tr.fc-sub td {
  background: #fcfcfd;
  font-size: 12px;
  border-top: none;
}

table.data-table tbody tr.fc-sub td.fc-sub-name {
  padding-left: 22px;
  color: var(--text-muted);
}

table.data-table tbody tr.fc-sub td.fc-sub-name strong {
  color: var(--ikon-purple);
}

/* Who the unbilled hours belong to. One node on the body, positioned by JS —
   inside the scrolling table the overflow would clip it. */
.fc-hours {
  border-bottom: 1px dotted var(--text-muted);
  cursor: help;
}

.fc-hours-pop {
  position: fixed;
  z-index: 3000;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 10px 12px;
  font-size: 12px;
  min-width: 240px;
}

.fc-hours-pop-title {
  font-weight: 600;
  margin-bottom: 6px;
}

.fc-hours-pop table {
  border-collapse: collapse;
  width: 100%;
}

.fc-hours-pop td {
  padding: 2px 0 2px 12px;
  white-space: nowrap;
}

.fc-hours-pop td:first-child {
  padding-left: 0;
}

.fc-hours-pop tr.fc-hours-pop-total td {
  border-top: 1px solid var(--border);
  font-weight: 600;
  padding-top: 4px;
}

/* A phase that is billed out. Still listed, because its project has phases
   left to claim and the project should read as a whole — but visibly done.
   Declared BEFORE the excluded colours below, so pushing a project to next
   month turns its finished phases red with the rest of it rather than leaving
   them grey and looking like they were left behind. */
table.data-table tbody tr.fc-done td {
  color: var(--text-muted);
  background: #fafafa;
}

/* Take a line off the forecast: the fee is spent, or the project is cancelled. */
.fc-remove {
  border: none;
  background: none;
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  border-radius: 4px;
}

.fc-remove:hover {
  color: #c0392b;
  background: #fbe9e7;
}

/* Work from before the cutover, riding along with this month's hours. */
.fc-prior {
  color: var(--ikon-purple);
  font-size: 11px;
  margin-top: 2px;
}

/* What a line forecast before its invoice was edited. */
.fc-was {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* The project number and the phase it is claiming. A long phase code — "LOT 5
   - DD" — is wider than the column, so the cell wraps the tag under the number
   rather than letting it run into the project name. Each part stays unbroken
   in itself. */
.fc-proj-cell {
  white-space: normal;
}

.fc-proj-cell .fc-open-project {
  white-space: nowrap;
}

.fc-phase-tag {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
  margin-left: 4px;
  padding: 0 5px;
  border-radius: 4px;
  background: var(--ikon-purple-light);
  color: var(--ikon-purple);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.3px;
}

/* Billable time with nothing to invoice against it. Red because it is a
   problem to fix, not a figure to read. */
table.data-table tbody tr.fc-no-claim td {
  color: #c0392b;
  background: #fffafa;
}

tr.fc-no-claim .fc-phase-tag {
  background: #fbe9e7;
  color: #c0392b;
}

tr.fc-no-claim .fc-no-claim-why,
tr.fc-no-claim .fc-no-claim-note {
  font-size: 11px;
}

.fc-no-claim-summary {
  color: #c0392b;
  font-size: 12px;
  margin: 6px 0 0;
}

/* Where a line has got to, at a glance — the Opportunities register's idiom,
   applied to td so it beats zebra striping, and last in the file so it beats
   the completed-phase grey above.
     red    pushed to next month
     amber  a draft exists, not yet with the client
     green  gone to the client */
table.data-table tbody tr.fc-excluded td { background: #fbe9e7; }
table.data-table tbody tr.fc-excluded:hover td { background: #f6ddd9; }
table.data-table tbody tr.fc-drafted td { background: #fdf1e0; }
table.data-table tbody tr.fc-drafted:hover td { background: #f8e6cc; }
table.data-table tbody tr.fc-sent td { background: #e7f4ea; }
table.data-table tbody tr.fc-sent:hover td { background: #d9edde; }
