:root {
  --text: #3d3a42;
  --text-h: #08060d;
  --bg: #fff;
  --bg-alt: #f7f6f9;
  --border: #e5e4e7;
  --accent: #7a3bff;
  --accent-text: #fff;

  --status-pass: #1a7f37;
  --status-pending: #9a6700;
  --error: #cf222e;

  --row-pass: #e4f3e7;
  --row-pending: #f3ebdd;
  --row-inactive: #eceaef;
  --row-hover: #e7dcff;

  --sans: system-ui, 'Segoe UI', Roboto, sans-serif;
  font: 16px/1.5 var(--sans);
  color-scheme: light dark;
  color: var(--text);
  background: var(--bg);
}

@media (prefers-color-scheme: dark) {
  :root {
    --text: #c7c5cc;
    --text-h: #f3f4f6;
    --bg: #16171d;
    --bg-alt: #1f2028;
    --border: #2e303a;
    --status-pass: #3fb950;
    --status-pending: #d29922;
    --error: #f85149;

    --row-pass: #1b2a1f;
    --row-pending: #2b2418;
    --row-inactive: #24252c;
    --row-hover: #332a4d;
  }
}

* { box-sizing: border-box; }
body { margin: 0; }
h1, h2, h3, h4 { color: var(--text-h); font-weight: 600; margin: 0 0 8px; }
h1 { font-size: 26px; }
h4 { font-size: 15px; margin-top: 16px; }
a { color: var(--accent); }
.muted { color: var(--text); opacity: 0.65; font-size: 14px; margin: 2px 0; }

.app-shell { min-height: 100svh; display: flex; flex-direction: column; }
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 24px; border-bottom: 1px solid var(--border);
}
.topbar-nav { display: flex; align-items: center; gap: 18px; font-size: 14px; }
.brand { font-weight: 700; font-size: 18px; text-decoration: none; color: var(--text-h); }
.topbar-user { display: flex; align-items: center; gap: 14px; font-size: 14px; }
/* Container widths follow Bootstrap's .container ladder so layouts match
   what we're used to: 540 / 720 / 960 / 1140 / 1320 at Bootstrap's
   sm/md/lg/xl/xxl breakpoints. On a 1920-wide screen this lands at 1320. */
.content { width: 100%; margin: 0 auto; padding: 24px; flex: 1; }
@media (min-width: 576px)  { .content { max-width: 540px; } }
@media (min-width: 768px)  { .content { max-width: 720px; } }
@media (min-width: 992px)  { .content { max-width: 960px; } }
@media (min-width: 1200px) { .content { max-width: 1140px; } }
@media (min-width: 1400px) { .content { max-width: 1320px; } }

.link-button {
  background: none; border: none; color: var(--accent); cursor: pointer;
  font-size: 14px; padding: 0; text-decoration: underline;
}

/* Both forms of control share every box metric — the transparent border
   included — so a <button> and a .button anchor sitting side by side are
   exactly the same height. */
button, .button {
  background: var(--accent); color: var(--accent-text);
  border: 1px solid transparent; border-radius: 6px;
  padding: 9px 16px; font-size: 14px; line-height: 1.5; cursor: pointer;
  font-family: inherit;
}
/* .button is the same control rendered as a link, for plain navigation —
   a <button> inside an <a> isn't valid HTML. */
.button { display: inline-block; text-decoration: none; }
button:disabled { opacity: 0.6; cursor: default; }
button.secondary, .button.secondary { background: var(--bg-alt); color: var(--text-h); border-color: var(--border); }

.page-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }

.auth-card {
  max-width: 380px; margin: 60px auto; padding: 28px; border: 1px solid var(--border);
  border-radius: 10px; background: var(--bg-alt);
}
.auth-subtitle { font-size: 14px; opacity: 0.75; margin-bottom: 16px; }
.auth-switch { margin-top: 16px; font-size: 14px; }
.demo-hint { margin-top: 20px; font-size: 12px; opacity: 0.65; line-height: 1.6; }
.demo-email-list { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.demo-email-list li { display: flex; align-items: center; }
.demo-email-copy {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  background: none; border: none; color: inherit; font-size: 12px; font-family: inherit;
  padding: 4px 0; cursor: pointer; opacity: 0.85; text-align: left;
}
.demo-email-copy:hover { opacity: 1; color: var(--accent); }
.demo-email-role { opacity: 0.6; font-size: 11px; white-space: nowrap; }

.form { display: flex; flex-direction: column; gap: 12px; }
.form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; font-weight: 500; }
.form input, .form select {
  font-size: 14px; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 6px; background: var(--bg); color: var(--text-h);
}
.form-error { color: var(--error); font-size: 14px; }
.form.card { padding: 16px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-alt); margin-bottom: 20px; }
.form-inline { flex-direction: row; flex-wrap: wrap; align-items: flex-end; gap: 12px; margin-top: 12px; }
.form-inline label { min-width: 140px; }
.form-inline .notes-label { flex: 1; min-width: 200px; }

.notice {
  background: var(--bg-alt); border: 1px solid var(--accent); border-radius: 8px;
  padding: 12px 16px; margin-bottom: 16px; font-size: 14px;
}

/* Confirmation of what a POST just did, and the error a rejected form
   comes back with. Both float rather than being inserted above the content,
   so nothing below them moves — a validation failure must not shove the form
   you're filling in down the page.

   The layer is fixed but tracks the container's width, so the toast sits
   against the *container's* right edge rather than the viewport's — on a
   wide screen that keeps it near what you were just looking at instead of
   off in the corner of the monitor. Widths mirror .content exactly. */
.toast-layer {
  position: fixed; top: 64px; left: 0; right: 0; z-index: 50;
  display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
  width: 100%; margin: 0 auto; padding: 0 24px; pointer-events: none;
}
@media (min-width: 576px)  { .toast-layer { max-width: 540px; } }
@media (min-width: 768px)  { .toast-layer { max-width: 720px; } }
@media (min-width: 992px)  { .toast-layer { max-width: 960px; } }
@media (min-width: 1200px) { .toast-layer { max-width: 1140px; } }
@media (min-width: 1400px) { .toast-layer { max-width: 1320px; } }

.toast {
  pointer-events: auto;
  max-width: 360px; background: var(--bg-alt);
  border: 1px solid var(--accent); border-radius: 8px;
  padding: 12px 16px; font-size: 14px; line-height: 1.45;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  animation: toast-fade 400ms ease 6s forwards;
}
/* An error stays put: it's the answer to something you just did wrong and
   has to still be there while you fix it. */
.toast-error { border-color: var(--error); color: var(--error); animation: none; }
.toast code { word-break: break-all; }
@keyframes toast-fade { to { opacity: 0; visibility: hidden; } }
@media (max-width: 600px) {
  .toast-layer { padding: 0 16px; }
  .toast { max-width: none; align-self: stretch; }
}

/* Lists share one shape: fixed layout so column widths are predictable,
   and every row the same height regardless of content length. Cells
   truncate to a single line with an ellipsis by default. Where wrapping
   is expected, put .table-2line on the table — rows then get the height
   of two lines and cells clamp to two. */
.table { width: 100%; border-collapse: collapse; font-size: 14px; table-layout: fixed; }
.table th, .table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); }
.table th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.6; }
.table td { height: 44px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.table-compact th, .table-compact td { padding: 6px 8px; font-size: 13px; }
.table-compact td { height: 34px; }

.table-2line td {
  height: 65px; white-space: normal;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
.table-compact.table-2line td { height: 53px; }

/* Row tint carries pass/pending, so lists don't need a separate risk column.
   A building whose policyholder hasn't accepted their invite yet is greyed
   out instead — its status isn't meaningful until someone's reporting. */
.row-pass { background: var(--row-pass); }
.row-pending { background: var(--row-pending); }
.row-inactive { background: var(--row-inactive); }
.row-inactive td { opacity: 0.7; }

/* Whole-row click target. The hover tint deliberately overrides the status
   tint so it's obvious which row you're about to open. */
.row-link { cursor: pointer; }
.row-link:hover, .row-link:focus-visible { background: var(--row-hover); outline: none; }
.row-link:hover td, .row-link:focus-visible td { opacity: 1; }

.badge {
  display: inline-block; font-size: 12px; font-weight: 600; padding: 3px 10px;
  border-radius: 999px; color: #fff;
}
/* Plain-text status, used where the label changes in place — a pill is
   taller than text, so swapping between the two resized the row and moved
   everything under it. Same metrics whichever state it's in. */
.status-text { font-size: 14px; font-weight: 500; color: var(--text); opacity: 0.75; }
.status-pass { color: var(--status-pass); opacity: 1; }
.status-pending { color: var(--status-pending); opacity: 1; }

.badge-pass { background: var(--status-pass); }
.badge-pending { background: var(--status-pending); }
.badge-account-active { background: var(--status-pass); }
.badge-account-pending { background: var(--status-pending); }

.system-list { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.system-panel { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.system-panel-absent { opacity: 0.6; }
.system-panel-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; cursor: pointer; background: var(--bg-alt);
}
.system-panel-title { font-weight: 600; font-size: 14px; }
.system-panel-meta { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.chevron { opacity: 0.5; }
.system-panel-body { padding: 16px; }
.checkbox-row { display: flex; align-items: center; gap: 8px; font-size: 14px; margin-bottom: 12px; }
.button-row { display: flex; gap: 8px; margin-bottom: 8px; }

.loading { padding: 40px; text-align: center; opacity: 0.6; }

/* Tabs — Bootstrap's nav-tabs shape: a bottom rule the active tab sits on
   top of, so the tab and the card below read as one surface. */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin-bottom: -1px; }
.tab {
  background: none; border: 1px solid transparent; border-bottom: none;
  border-radius: 6px 6px 0 0; padding: 9px 16px; font-size: 14px;
  color: var(--text-h); cursor: pointer; text-decoration: none;
  display: inline-block; line-height: 1.5;
}
.tab:hover { background: var(--bg-alt); }
/* Only the surface changes when a tab is selected — the label's weight and
   colour stay put, so tab widths don't shift as you switch between them. */
.tab-active, .tab-active:hover {
  background: var(--bg); border-color: var(--border);
}

.card { border: 1px solid var(--border); border-radius: 8px; background: var(--bg); }
.tabs + .card { border-top-left-radius: 0; }
.card-header {
  padding: 12px 16px; border-bottom: 1px solid var(--border);
  background: var(--bg-alt); font-weight: 600; font-size: 14px;
  border-radius: 8px 8px 0 0;
}
.card-body { padding: 16px; }
/* Page actions sit bottom right, primary first then Cancel — in a card's
   footer when there is one, otherwise on their own row at the end of the
   page. Same place on every page, so the button you want is always where
   you last left it. */
.card-footer {
  padding: 12px 16px; border-top: 1px solid var(--border);
  background: var(--bg-alt); display: flex; gap: 8px; align-items: center;
  justify-content: flex-end; border-radius: 0 0 8px 8px;
}
/* Anything pushed to the far left of the footer — an action that isn't one
   of the pair, such as resending an invite. */
.card-footer > .footer-start { margin-right: auto; }
.page-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }

/* Two-column field grid that collapses to one column on narrow screens. */
.field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; }
.field-grid .field-wide { grid-column: 1 / -1; }
@media (max-width: 767px) { .field-grid { grid-template-columns: minmax(0, 1fr); } }
.field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; font-weight: 500; }
.field input, .field select {
  font-size: 14px; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 6px; background: var(--bg); color: var(--text-h); width: 100%;
}
.field input:read-only { background: var(--bg-alt); color: var(--text); }

/* Input group — control plus trailing buttons sharing one rounded outline. */
.input-group { display: flex; }
.input-group > input { flex: 1; min-width: 0; border-radius: 6px 0 0 6px; }
.input-group > button, .input-group > .input-group-button {
  border-radius: 0; border: 1px solid var(--border); border-left: none;
  background: var(--bg-alt); color: var(--text-h); padding: 0 12px;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
}
.input-group > :last-child { border-radius: 0 6px 6px 0; }
.input-group > button:hover, .input-group > .input-group-button:hover { background: var(--border); }
.input-group > .input-group-button {
  text-decoration: none; font-size: 14px; align-self: stretch;
}
.icon { width: 16px; height: 16px; flex: none; }

/* Modal */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 60px 16px; z-index: 20;
}
.modal { background: var(--bg); border-radius: 10px; width: 100%; max-width: 520px; max-height: 80vh; display: flex; flex-direction: column; }
.modal .card-body { overflow-y: auto; }
.picker-list { list-style: none; margin: 12px 0 0; padding: 0; }
.picker-list button {
  width: 100%; text-align: left; background: none; border: none;
  border-bottom: 1px solid var(--border); color: var(--text-h);
  padding: 10px 8px; cursor: pointer; border-radius: 0;
}
.picker-list button:hover { background: var(--row-hover); }
.picker-current { opacity: 0.6; font-size: 12px; }

/* Tab body that isn't a card — still sits below the tab strip's rule. */
.tab-panel { padding-top: 16px; }

.system-card-header { display: flex; align-items: center; justify-content: space-between; }

/* Carry the list row's tint onto the card you opened from it, so the status
   you saw in the list is still the status you see here. Qualified with
   .card-header so it beats the header's own background. */
.card-header.header-pass { background: var(--row-pass); }
.card-header.header-pending { background: var(--row-pending); }
.card-header.header-inactive { background: var(--row-inactive); }

/* Breadcrumbs sit directly under the topbar, above the page's own heading. */
.breadcrumbs { display: flex; flex-wrap: wrap; align-items: center; font-size: 13px; margin-bottom: 16px; }
.crumb { display: inline-flex; align-items: center; }
.crumb-sep { margin: 0 8px; opacity: 0.4; }
.breadcrumbs a { text-decoration: none; }
.breadcrumbs a:hover { text-decoration: underline; }
.breadcrumbs [aria-current="page"] { color: var(--text-h); font-weight: 500; }

/* Holds a page's height while its content loads, so arriving on a page
   doesn't collapse the layout to a line and then push it back down. */
.panel-placeholder { min-height: 320px; }

/* A form that's just a button sitting inline with surrounding text. */
.inline-form { display: inline-block; margin: 0; }
.form .inline-form button { margin-top: 0; }

/* Links styled as table cells shouldn't fight the whole-row click target. */
.table a { color: inherit; text-decoration: none; }
.table a:hover { text-decoration: underline; }

/* Dashboard tiles — cards that are entirely a link. */
.tile-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px; margin-top: 20px;
}
.tile {
  display: flex; flex-direction: column; gap: 6px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--bg);
  padding: 20px; text-decoration: none; color: var(--text);
}
.tile:hover { background: var(--row-hover); }
.tile-title { font-size: 16px; font-weight: 600; color: var(--text-h); }
.tile-desc { font-size: 14px; }
.tile-meta { font-size: 13px; opacity: 0.65; margin-top: 4px; }

/* Inline note after a section heading, e.g. "Contractor (invited 01/01/26)". */
h4 .muted { font-weight: 400; font-size: 13px; }

.table .cell-centre { text-align: center; }

/* The row you last opened from this list: a bar down its left edge, drawn
   as an inset shadow inside the cell, so it costs no width and nothing
   moves. The row keeps its own background, so the pass/pending/grey tint
   stays readable.

   Only the first cell is marked. The table uses border-collapse, so a rule
   along the top and bottom of the row lands directly on the neighbouring
   rows' collapsed borders and reads as a doubled, muddy line. */
.row-selected td:first-child {
  box-shadow: inset 4px 0 0 var(--accent);
}
