/* Visual system (2026-08-06): red-and-black/red-and-white, per Peyton's
   direction -- Vulcan (Roman god of fire/the forge) and welding's own
   fire-and-electricity nature, not a generic SaaS purple. Red stays the
   one hero color in both themes rather than competing with a second
   accent hue; --accent-2 exists only for gradient fills (bar charts,
   the brand mark) moving through red's own family toward ember-orange,
   never introducing an unrelated hue. --graphite/--graphite-light are the
   sidebar/topbar's permanently-dark chrome -- unlike --bg/--panel-bg
   (which do switch with the theme), the nav chrome stays dark in both
   modes as a fixed brand anchor, the same pattern GitHub/Linear/Vercel
   use. */
@font-face {
  font-family: "Big Shoulders Display";
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  src: url("fonts/big-shoulders-display-800.woff2") format("woff2");
}
/* Saira Condensed -- the closest free match to the Brontes wordmark
   (2026-08-29 rename). Self-hosted latin subset, pulled from Google Fonts
   at build time rather than linked from fonts.googleapis.com, matching how
   the other three faces here are already served: no third-party request on
   every page load, and no dependency on Google being reachable. */
@font-face {
  font-family: "Saira Condensed";
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  src: url("fonts/saira-condensed-700.woff2") format("woff2");
}
@font-face {
  font-family: "Manrope";
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
  src: url("fonts/manrope-500.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  src: url("fonts/plex-mono-500.woff2") format("woff2");
}

:root {
  --ink: #141414;
  --graphite: #101013;
  --graphite-light: #1c1c21;
  --steel: #8a8a8a;
  --steel-light: #b0b0b0;
  --bg: #f7f6f4;
  --panel-bg: #ffffff;
  --panel-alt: #efece9;
  --border: #e7e4e2;
  --text: #141414;
  --text-muted: #6b6b6b;
  --accent: #c81616;
  --accent-2: #e8560f;
  --accent-dark: #a01010;
  --accent-tint: #fdeceb;
  --success: #1f8a54;
  --success-tint: #e4f7ec;
  --danger: #c81616;
  --danger-tint: #fdeceb;
  --warn: #e8560f;
  --warn-tint: #fdeee5;
  --sidebar-text: #a3a3a8;
  --sidebar-text-active: #ffffff;
  --shadow: 0 10px 26px -14px rgba(20,16,14,0.16);
  --header-grad: linear-gradient(120deg, #3a0505 0%, #7a1010 38%, #c81616 68%, #e8560f 100%);
}

/* Dark theme (2026-08-06, revised): a true near-black background read as
   flat/harsh rather than "modern" (Peyton's direct feedback against the
   first pass) -- real dark-mode dashboards (GitHub, Linear, Vercel) use a
   warm-neutral charcoal, not pure black, and give panels a clearly
   lighter step so cards visibly separate from the page instead of
   blending into it. --bg/--panel-bg/--panel-alt are three distinct
   lightness steps now, not two-that-look-like-one. */
@media (prefers-color-scheme: dark) {
  :root {
    --ink: #f5f5f3;
    --steel: #86868c;
    --steel-light: #a3a3a9;
    --bg: #16161a;
    --panel-bg: #1e1e24;
    --panel-alt: #29292f;
    --border: #34343c;
    --text: #f5f5f3;
    --text-muted: #96969d;
    --accent: #e21c1c;
    --accent-2: #ff5a1f;
    --accent-dark: #b81414;
    --accent-tint: rgba(226,28,28,0.18);
    --success: #34d399;
    --success-tint: rgba(52,211,153,0.16);
    --danger: #e21c1c;
    --danger-tint: rgba(226,28,28,0.18);
    --warn: #ff5a1f;
    --warn-tint: rgba(255,90,31,0.18);
    --shadow: 0 14px 34px -14px rgba(0,0,0,0.55);
    --header-grad: linear-gradient(120deg, #3a0505 0%, #7a1010 38%, #e21c1c 68%, #ff8a3d 100%);
  }
}
:root[data-theme="dark"] {
  --ink: #f5f5f3; --steel: #86868c; --steel-light: #a3a3a9;
  --bg: #16161a; --panel-bg: #1e1e24; --panel-alt: #29292f; --border: #34343c;
  --text: #f5f5f3; --text-muted: #96969d;
  --accent: #e21c1c; --accent-2: #ff5a1f; --accent-dark: #b81414;
  --accent-tint: rgba(226,28,28,0.18); --success: #34d399; --success-tint: rgba(52,211,153,0.16);
  --danger: #e21c1c; --danger-tint: rgba(226,28,28,0.18); --warn: #ff5a1f; --warn-tint: rgba(255,90,31,0.18);
  --shadow: 0 14px 34px -14px rgba(0,0,0,0.55);
  --header-grad: linear-gradient(120deg, #3a0505 0%, #7a1010 38%, #e21c1c 68%, #ff8a3d 100%);
}
:root[data-theme="light"] {
  --ink: #141414; --steel: #8a8a8a; --steel-light: #b0b0b0;
  --bg: #f7f6f4; --panel-bg: #ffffff; --panel-alt: #efece9; --border: #e7e4e2;
  --text: #141414; --text-muted: #6b6b6b;
  --accent: #c81616; --accent-2: #e8560f; --accent-dark: #a01010;
  --accent-tint: #fdeceb; --success: #1f8a54; --success-tint: #e4f7ec;
  --danger: #c81616; --danger-tint: #fdeceb; --warn: #e8560f; --warn-tint: #fdeee5;
  --shadow: 0 10px 26px -14px rgba(20,16,14,0.16);
  --header-grad: linear-gradient(120deg, #3a0505 0%, #7a1010 38%, #c81616 68%, #e8560f 100%);
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: "Manrope", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  /* Chrome/Edge render native checkboxes, radios, and range inputs with
     a default blue accent-color unless told otherwise -- without this
     every checkbox in the app (review-before-save screens, etc.) shows
     up blue regardless of the red visual system everywhere else. */
  accent-color: var(--accent);
  -webkit-font-smoothing: antialiased;
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* Safety-net fallback for any input/select/button not already covered by
   a more specific :focus rule elsewhere -- browsers default an unstyled
   focus ring to blue, which would otherwise be the one leftover blue
   spot in an all-red-accent app. */
input:focus, select:focus, textarea:focus, button:focus-visible, a:focus-visible {
  outline-color: var(--accent);
}

/* Global link fallback -- this app has ~150 templates and dozens of
   plain <a href> tags outside .data-table/.file-list/etc (e.g. a bare
   link in a paragraph like Admin Settings' link to console.anthropic.com).
   Without this they fall back to the browser's default blue, the one
   leftover blue spot after fixing accent-color on form controls. Low
   specificity on purpose -- every existing more-specific link rule
   (.data-table a, .module-card, .nav-dropdown a, ...) still wins. */
a {
  color: var(--accent);
  text-decoration: none;
}
a:hover {
  color: var(--accent-dark);
}

/* Display face switched from Big Shoulders Display to Saira Condensed with
   the Brontes rename, so UI type sits next to the wordmark without clashing.
   This one rule covers every display element in the app -- headings, the
   brand name, tabs, buttons, badges, stat values -- so it is also the single
   line to change back if the pairing doesn't hold up in practice. Body type
   (Manrope) is untouched. Big Shoulders stays first in no stack; its woff2
   is still on disk and can be dropped once this is settled. */
h1, h2, h3, .brand-name, .tabs a, .btn, .badge, .stat-value {
  font-family: "Saira Condensed", "Big Shoulders Display", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}

/* App shell: a permanently-dark left sidebar (brand chrome, doesn't
   switch with the light/dark content theme -- see the --graphite note
   above) plus a theme-following main content column. Replaces the old
   horizontal .topbar/.tabs nav entirely (2026-08-06). */
.app-shell {
  display: flex;
  align-items: stretch;
  min-height: 100vh;
}

.sidebar {
  width: 244px;
  flex-shrink: 0;
  background: var(--graphite);
  color: var(--sidebar-text);
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 20px 14px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 6px 4px;
}

.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 15px;
  font-weight: 800;
  flex-shrink: 0;
  box-shadow: 0 6px 16px -6px rgba(226,28,28,0.6);
}

.brand-name {
  color: #fff;
  font-size: 0.92rem;
  line-height: 1.15;
  letter-spacing: 0.02em;
}

.brand-logo {
  height: 28px;
  max-width: 160px;
  object-fit: contain;
}

/* Brontes mark (2026-08-29). Raster artwork on a black background with no
   knockout version yet, so it may only sit on dark chrome -- which both of
   its placements already are: the app sidebar is permanently dark in both
   themes (see the App shell comment above) and .mkt-nav is --graphite. Do
   not reuse this class on a light surface until a knockout exists. Native
   art is 440x440; rendered well below that, never above. */
.brand-mark-img {
  width: 34px;
  height: 34px;
  border-radius: 8px;
  object-fit: contain;
  flex: none;
}

/* Lockup plate. The artwork is raster on solid black with no knockout, so
   rather than hope each host surface is dark enough, it carries its own
   near-black plate -- which reads as deliberate framing on the red
   --header-grad hero and on a light-mode login page alike. Remove the plate
   (not the class) once vector/knockout versions exist.
   Native art is 745x426 (Brontes) and 914x647 (Vulcan); every cap below is
   well under those, since raster must never be scaled up. */
.brand-lockup {
  background: #0b0b0d;
  border-radius: 12px;
  padding: 14px 18px;
  margin: 0 auto 22px;
  display: flex;
  justify-content: center;
}

.brand-lockup img {
  display: block;
  width: 100%;
  height: auto;
}

.brand-lockup-auth {
  max-width: 320px;
}

.brand-lockup-hero {
  max-width: 420px;
  margin-left: 0;
  margin-right: 0;
}

/* Footer sits on --graphite already, so the company lockup needs no plate
   of its own -- just a size cap. */
.brand-lockup-company {
  max-width: 200px;
  height: auto;
  display: block;
}

.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 18px;
  overflow-y: auto;
  flex: 1;
}

.nav-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nav-group-label {
  font-family: "Manrope", sans-serif;
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #6b6b70;
  padding: 0 10px;
  margin-bottom: 2px;
}

/* Module-header dropdown nav (2026-08-06, reworked into a sidebar
   accordion) -- a plain nav row optionally paired with a caret that
   expands its module's secondary views (Dashboard, Pipeline, Calendar,
   etc.) inline underneath, instead of those living as separate per-page
   header buttons. Click-to-toggle, not hover, so it works the same on
   touch devices -- no JS framework, just base.html's inline script. */
.nav-item {
  display: flex;
  flex-direction: column;
}

.nav-item > a {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--sidebar-text);
  text-decoration: none;
  font-family: "Manrope", sans-serif;
  font-size: 0.83rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: none;
  transition: background 0.12s ease, color 0.12s ease;
}

.nav-item > a:hover {
  background: var(--graphite-light);
  color: var(--sidebar-text-active);
}

.nav-item > a.active {
  background: linear-gradient(90deg, rgba(226,28,28,0.22), rgba(255,90,31,0.05));
  color: var(--sidebar-text-active);
  box-shadow: inset 2px 0 0 var(--accent);
}

.nav-row {
  display: flex;
  align-items: stretch;
}

.nav-row > a {
  flex: 1;
}

.nav-caret {
  background: none;
  border: none;
  color: var(--sidebar-text);
  cursor: pointer;
  padding: 0 10px;
  font-size: 0.65rem;
  transition: color 0.15s ease, transform 0.15s ease;
}

.nav-caret:hover,
.nav-item.open .nav-caret {
  color: var(--sidebar-text-active);
}

.nav-item.open .nav-caret {
  transform: rotate(180deg);
}

.nav-dropdown {
  display: none;
  flex-direction: column;
  padding: 3px 0 3px 14px;
  margin-top: 1px;
  gap: 1px;
  border-left: 1px solid var(--graphite-light);
  margin-left: 20px;
}

.nav-item.open .nav-dropdown {
  display: flex;
}

.nav-dropdown a {
  display: block;
  padding: 7px 10px;
  border-radius: 7px;
  color: #9c9ca2;
  text-decoration: none;
  font-family: "Manrope", sans-serif;
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-transform: none;
}

.nav-dropdown a:hover,
.nav-dropdown a.active {
  background: var(--graphite-light);
  color: var(--sidebar-text-active);
}

.sidebar-footer {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border-radius: 10px;
  background: var(--graphite-light);
}

.sidebar-user {
  display: flex;
  align-items: center;
  gap: 9px;
}

.sidebar-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  color: #fff;
  font-family: "Big Shoulders Display", sans-serif;
  font-weight: 800;
  font-size: 11.5px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.sidebar-user-text {
  font-size: 0.76rem;
  line-height: 1.3;
  color: #d7d7db;
  overflow: hidden;
}

.sidebar-user-text .role {
  color: #7f7f85;
  font-size: 0.7rem;
}

.sidebar-footer-links {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

.theme-toggle {
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.12);
  color: var(--sidebar-text);
  border-radius: 7px;
  padding: 6px 9px;
  font-size: 0.72rem;
  font-weight: 700;
  cursor: pointer;
  font-family: "Manrope", sans-serif;
}

.theme-toggle:hover {
  background: rgba(255,255,255,0.12);
  color: #fff;
}

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

/* Bids/Estimating list toggle (2026-08-06, Phase 3) -- the two lists stay
   separate data/routes, this is just a quick switch between them living on
   the list pages themselves, distinct from the combined nav dropdown. */
.list-toggle {
  display: inline-flex;
  border: 1px solid var(--border, #d7dde3);
  border-radius: 6px;
  overflow: hidden;
  margin-bottom: 16px;
}

.list-toggle a {
  padding: 8px 18px;
  text-decoration: none;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.list-toggle a.active {
  background: var(--accent);
  color: #fff;
}

/* Inline click-to-edit fields (2026-08-06, Phase 4 -- the first React-
   mounted component, replacing full Edit forms on the Estimate and
   Customer detail pages per Peyton's explicit request). */
.inline-edit-display {
  cursor: text;
  border-bottom: 1px dashed transparent;
}

.inline-edit-display:hover {
  border-bottom-color: var(--accent);
  background: var(--accent-tint);
}

.inline-edit-display em {
  color: var(--text-muted);
  font-style: italic;
}

.inline-edit-error {
  border-bottom-color: #b33c3c;
}

.inline-edit-error-badge {
  color: #b33c3c;
  font-size: 0.78rem;
}

.inline-edit-input {
  font: inherit;
  padding: 2px 6px;
  border: 1px solid var(--accent);
  border-radius: 12px;
  min-width: 120px;
}

.content {
  max-width: 1180px;
  margin: 0 auto;
  padding: 34px 30px 60px;
  width: 100%;
  /* .app-shell is a flex row (sidebar + .content) -- flex items default
     to min-width: auto, which refuses to shrink below their content's
     natural width. Without this override, a wide table anywhere inside
     .content (e.g. the Projects import review "Assemblies & Parts"
     table, 10 dense columns) pushes .content itself wider than the
     viewport instead of being contained by an inner .table-scroll's
     overflow-x: auto -- the whole page scrolls sideways (dragging the
     sidebar with it) instead of just the table. */
  min-width: 0;
}

.footer {
  text-align: center;
  color: var(--text-muted);
  font-size: 0.78rem;
  padding: 20px;
  letter-spacing: 0.02em;
}

.page-title {
  font-size: 1.7rem;
  font-weight: 800;
  margin: 0 0 18px;
  color: var(--ink);
  letter-spacing: 0.01em;
}

/* The gradient hero band (2026-08-06) -- carried over from the reference
   image's boldest element, which the first pass at this redesign dropped
   entirely. Scoped to .page-header .page-title/.subtitle rather than
   .page-title globally: plenty of pages (forms, Admin Settings, the
   Dashboard) use a bare <h1 class="page-title"> with no .page-header
   wrapper, and those must keep reading against the normal page
   background, not turn invisible white-on-white. */
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin: 0 0 22px;
  gap: 12px;
  flex-wrap: wrap;
  background: var(--header-grad);
  border-radius: 16px;
  padding: 24px 28px;
  box-shadow: var(--shadow);
}

.page-header .page-title {
  color: #fff;
  margin: 0;
}

.page-header .subtitle {
  color: rgba(255,255,255,0.82);
}

.subtitle {
  color: var(--text-muted);
  margin: 2px 0 0;
  font-size: 0.95rem;
}

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

.page-header .header-actions .btn-secondary {
  background: rgba(255,255,255,0.14);
  border-color: rgba(255,255,255,0.34);
  color: #fff;
}

.page-header .header-actions .btn-secondary:hover {
  background: rgba(255,255,255,0.26);
}

.page-header .header-actions .btn-primary {
  background: #fff;
  color: var(--accent-dark);
}

.page-header .header-actions .btn-primary:hover {
  background: rgba(255,255,255,0.86);
}

.page-header .header-actions .btn-danger {
  background: rgba(0,0,0,0.2);
  color: #fff;
  border-color: rgba(255,255,255,0.4);
}

.page-header .header-actions .btn-danger:hover {
  background: rgba(0,0,0,0.34);
}

/* Stat cards */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px;
  margin-bottom: 28px;
}

.stat-card {
  display: block;
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 18px;
  text-align: center;
  text-decoration: none;
  color: var(--ink);
  box-shadow: var(--shadow);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.stat-card:hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 30px -14px rgba(200,22,22,0.28);
}

.stat-value {
  font-size: 2.1rem;
  font-weight: 600;
  color: var(--ink);
}

.stat-label {
  color: var(--text-muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 4px;
}

.trend-chart {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.trend-row {
  display: grid;
  grid-template-columns: 90px 1fr 90px;
  align-items: center;
  gap: 10px;
}

.trend-label {
  font-size: 0.85rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.trend-track {
  background: var(--accent-tint);
  border-radius: 8px;
  height: 18px;
  overflow: hidden;
}

.trend-fill {
  background: var(--accent);
  height: 100%;
  border-radius: 3px 0 0 3px;
  min-width: 2px;
}

.trend-value {
  font-size: 0.85rem;
  font-family: "IBM Plex Mono", monospace;
  text-align: right;
}

.trend-fill-ok { background: #2f7d4f; }
.trend-fill-warn { background: #c98a1b; }
.trend-fill-over { background: #b33c3c; }
.trend-fill-unset { background: var(--border); }

/* Panels & layout */
.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-bottom: 20px;
}

.file-groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 20px;
  margin-bottom: 20px;
}

.panel {
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px 22px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
}

.panel h2 {
  margin-top: 0;
  font-size: 0.95rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink);
  border-bottom: 1px solid var(--border);
  padding-bottom: 10px;
  margin-bottom: 16px;
}

.empty {
  color: var(--text-muted);
  font-style: italic;
}

.subtle {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.section-label {
  font-family: "Big Shoulders Display", sans-serif;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  margin: 28px 0 12px;
  border: none;
  padding: 0;
}

/* Module link cards -- for pages that link out to dedicated feature pages
   instead of stacking everything inline */
.module-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
  margin-bottom: 24px;
}

.module-card {
  display: block;
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
  padding: 16px 18px;
  text-decoration: none;
  color: var(--ink);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.module-card:hover {
  border-left-color: var(--accent-dark);
  box-shadow: 0 2px 10px rgba(16, 21, 27, 0.08);
}

.module-card-title {
  font-family: "Big Shoulders Display", sans-serif;
  font-weight: 600;
  font-size: 1.02rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.module-card-count {
  color: var(--accent);
  font-size: 0.9rem;
}

.module-card-desc {
  color: var(--text-muted);
  font-size: 0.82rem;
  margin-top: 6px;
}

/* Tables */
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

/* Wrap a wide .data-table in this when it has enough columns to
   realistically overflow its .panel card (e.g. Projects import review's
   Assemblies & Parts table) -- scrolls the table itself horizontally
   instead of blowing out the page layout. */
.table-scroll {
  overflow-x: auto;
}

.data-table th {
  text-align: left;
  color: var(--text-muted);
  text-transform: uppercase;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  border-bottom: 2px solid var(--border);
  padding: 8px 10px;
}

.data-table td {
  padding: 10px;
  border-bottom: 1px solid var(--border);
}

.data-table a {
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
}

.data-table a:hover {
  color: var(--accent);
}

/* Badges: tinted pills (2026-08-06 visual redesign) rather than solid
   fills with white text -- softer, and the tint automatically follows
   the light/dark theme since it's built from the same status-semantic
   tokens (--success/--warn/--danger + their -tint pairs) everything
   else uses, not a separate one-off palette. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--panel-alt);
  color: var(--text-muted);
}

.badge::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

.badge-draft, .badge-status, .badge-reviewing, .badge-canceled { background: var(--panel-alt); color: var(--text-muted); }
.badge-open, .badge-sent { background: var(--warn-tint); color: var(--warn); }
.badge-won, .badge-accepted { background: var(--success-tint); color: var(--success); }
.badge-lost, .badge-declined { background: var(--danger-tint); color: var(--danger); }
.badge-shop { background: var(--accent-tint); color: var(--accent); }
.badge-superseded { background: var(--warn-tint); color: var(--warn); }

.badge-bid-new-bid, .badge-bid-open { background: var(--warn-tint); color: var(--warn); }
.badge-bid-reviewing { background: var(--accent-tint); color: var(--accent); }
.badge-bid-accepted { background: var(--success-tint); color: var(--success); }
.badge-bid-declined, .badge-bid-canceled { background: var(--danger-tint); color: var(--danger); }

/* Buttons */
.btn {
  display: inline-block;
  padding: 9px 16px;
  border-radius: 8px;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-decoration: none;
  border: none;
  cursor: pointer;
}

.btn-sm {
  padding: 6px 12px;
  font-size: 0.72rem;
}

.btn-primary {
  background: var(--accent);
  color: #fff;
}

.btn-primary:hover {
  background: var(--accent-dark);
}

.btn-secondary {
  background: var(--panel-bg);
  color: var(--ink);
  border: 1px solid var(--border);
}

.btn-secondary:hover {
  background: var(--panel-alt);
  border-color: var(--steel-light);
}

.btn-danger {
  background: var(--panel-bg);
  color: var(--danger);
  border: 1px solid var(--danger);
}

.btn-danger:hover {
  background: var(--danger);
  color: #fff;
}

/* Forms */
.card-form {
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 24px;
  max-width: 720px;
  box-shadow: var(--shadow);
}

.form-row {
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-row label {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}

.form-row input,
.form-row select,
.form-row textarea {
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.92rem;
  font-family: inherit;
  background: var(--panel-bg);
  color: var(--text);
}

.form-row input:focus,
.form-row select:focus,
.form-row textarea:focus,
.inline-form input:focus,
.inline-form select:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.form-grid-3 {
  grid-template-columns: 1fr 1fr 1fr;
}

.form-grid-4 {
  grid-template-columns: 1fr 1fr 1fr 1fr;
}

.checkbox-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
}

.checkbox-inline {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: normal;
}

.form-actions {
  display: flex;
  gap: 10px;
  margin-top: 8px;
}

.inline-form {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px dashed var(--border);
}

.inline-form input,
.inline-form select {
  padding: 7px 8px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.85rem;
}

.inline-form input[type="text"] {
  flex: 1;
  min-width: 160px;
}

/* Detail list */
.detail-list {
  display: grid;
  grid-template-columns: 140px 1fr;
  row-gap: 10px;
  column-gap: 10px;
  margin: 0;
}

.detail-list dt {
  color: var(--text-muted);
  font-size: 0.76rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.detail-list dd {
  margin: 0;
}

.totals-panel .detail-list {
  grid-template-columns: 1fr auto;
  max-width: 360px;
  margin-left: auto;
}

.grand-total-label {
  font-weight: 700;
  color: var(--ink);
  border-top: 2px solid var(--border);
  padding-top: 8px;
}

.grand-total-value {
  font-weight: 700;
  color: var(--accent);
  font-size: 1.15rem;
  border-top: 2px solid var(--border);
  padding-top: 8px;
}

/* Kanban board */
.kanban {
  display: grid;
  grid-template-columns: repeat(8, minmax(180px, 1fr));
  gap: 12px;
  overflow-x: auto;
}

.kanban-col {
  background: var(--panel-alt);
  border-radius: 10px;
  padding: 10px;
  min-height: 200px;
}

.kanban-col h3 {
  font-size: 0.76rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink);
  margin: 4px 6px 10px;
  display: flex;
  justify-content: space-between;
}

.kanban-col h3 .count {
  color: var(--text-muted);
  font-weight: 400;
}

.kanban-col-cards {
  min-height: 40px;
}

.kanban-card {
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  padding: 10px;
  margin-bottom: 10px;
  font-size: 0.82rem;
}

.kanban-card-link {
  display: block;
  text-decoration: none;
  color: inherit;
}

.kanban-card-stalled {
  border-left-color: var(--danger);
}

.kanban-card-title {
  display: block;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  margin-bottom: 4px;
}

.kanban-card-desc {
  margin-bottom: 6px;
}

.kanban-card-meta {
  color: var(--text-muted);
  font-size: 0.75rem;
}

.inline-status-select {
  padding: 4px 6px;
  border-radius: 6px;
  border: 1px solid var(--border);
  font-size: 0.75rem;
  background: var(--panel-bg);
  color: var(--text);
}

.kanban-status-form select {
  width: 100%;
  margin-top: 8px;
  padding: 5px;
  border-radius: 8px;
  border: 1px solid var(--border);
  font-size: 0.75rem;
}

.status-update-form {
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.status-update-form select {
  padding: 7px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
}

/* File uploads */
.folder-path {
  font-family: "IBM Plex Mono", Consolas, "Courier New", monospace;
  font-size: 0.72rem;
  color: var(--text-muted);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 8px;
  margin: 0 0 12px;
  word-break: break-all;
}

.file-list {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
}

.file-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.88rem;
}

.file-list li a {
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  flex: 1;
}

.file-list li a:hover {
  color: var(--accent);
}

.file-meta {
  color: var(--text-muted);
  font-size: 0.78rem;
  font-family: "IBM Plex Mono", Consolas, monospace;
}

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}

.cal-head {
  background: var(--panel-bg);
  padding: 8px;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  text-align: center;
}

.cal-cell {
  background: var(--panel-bg);
  min-height: 92px;
  min-width: 0;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.cal-cell-empty {
  background: var(--bg);
}

.cal-day-num {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-bottom: 2px;
}

.cal-bid-pill {
  display: block;
  color: #fff;
  font-size: 0.72rem;
  padding: 2px 6px;
  border-radius: 12px;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upload-form {
  display: flex;
  gap: 8px;
  align-items: center;
  padding-top: 12px;
  border-top: 1px dashed var(--border);
  flex-wrap: wrap;
}

.upload-form input[type="file"] {
  flex: 1;
  min-width: 180px;
  font-size: 0.82rem;
}

/* Drag-and-drop drop zone (2026-09-02, auto-processing drop zone) --
   wraps the same <input type="file"> the plain upload form always had
   (see static/js/drop-zone.js), so this is purely visual: dashed border
   at rest, solid accent highlight while a drag is over it. */
.drop-zone {
  display: flex;
  flex: 1;
  min-width: 220px;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border: 2px dashed var(--border);
  border-radius: 10px;
  background: var(--panel-alt, var(--bg));
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.drop-zone:focus-within,
.drop-zone.drag-over {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--panel-alt, var(--bg)));
}

.drop-zone-icon {
  flex-shrink: 0;
  color: var(--text-muted);
}

.drop-zone.drag-over .drop-zone-icon {
  color: var(--accent);
}

.drop-zone-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.drop-zone-text {
  font-size: 0.85rem;
  font-weight: 600;
}

.drop-zone-hint {
  font-size: 0.75rem;
  color: var(--text-muted);
}

.drop-zone input[type="file"] {
  /* Visually hidden but still a real, focusable, clickable file input --
     clicking anywhere on the zone (a <label>) opens the native picker,
     and keyboard/screen-reader users tab to it normally. Not display:none
     (that would drop it from the tab order in some browsers). */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

/* Flash messages */
.flash-wrap {
  margin-bottom: 18px;
}

.flash {
  padding: 10px 14px;
  border-radius: 8px;
  margin-bottom: 8px;
  font-size: 0.88rem;
  border-left: 3px solid transparent;
}

.flash-success {
  background: var(--success-tint);
  color: var(--success);
  border-left-color: var(--success);
}

.flash-error {
  background: var(--danger-tint);
  color: var(--danger);
  border-left-color: var(--danger);
}

@media (max-width: 900px) {
  .two-col, .form-grid, .form-grid-3, .stat-grid {
    grid-template-columns: 1fr;
  }
  .kanban {
    grid-template-columns: repeat(8, 220px);
  }
  .app-shell {
    flex-direction: column;
  }
  .sidebar {
    width: 100%;
    height: auto;
    position: relative;
  }
}

.auth-area {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.72rem;
  flex-wrap: wrap;
}

.auth-area a {
  color: var(--sidebar-text);
  text-decoration: none;
  font-weight: 600;
}

.auth-area a:hover {
  color: #fff;
}

.auth-user {
  color: #7f7f85;
  flex-basis: 100%;
}

.inline-logout {
  display: inline;
}

.auth-wrap {
  max-width: 380px;
  margin: 40px auto;
}

.lowest-bid {
  background: var(--success-tint);
}

/* Scope Leveler (Bid Invitation Phase 2 Task 9, 2026-08-20) -- proposals grouped by trade,
   each rendered as its own card rather than a table row so a leveled proposal's variable-
   height Scope/Qualifications/Exclusions checkbox lists have room to expand. */
.panel-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--border);
  padding-bottom: 10px;
  margin-bottom: 16px;
}

.panel-header-row h2.panel-header-row-title {
  margin: 0;
  border: none;
  padding: 0;
}

.leveler-trade-group {
  margin-bottom: 24px;
}

.leveler-trade-group:last-child {
  margin-bottom: 20px;
}

.leveler-proposal-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  margin-bottom: 12px;
}

.leveler-proposal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.leveler-proposal-title {
  display: flex;
  align-items: center;
  gap: 8px;
}

.leveler-proposal-amount {
  font-weight: 700;
  font-size: 1.05rem;
}

.leveler-proposal-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  color: var(--text-muted);
  font-size: 0.85rem;
  margin-top: 6px;
}

.leveler-item-groups {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}

.leveler-item-actions {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
}

.leveler-item-kind {
  margin-bottom: 10px;
}

.leveler-item-kind .section-label {
  margin: 0 0 6px;
  font-size: 0.72rem;
}

.leveler-item-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.leveler-item-list form {
  margin: 0;
}

.leveler-proposal-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}

/* Gantt chart */
.gantt-wrap {
  overflow-x: auto;
}

.gantt {
  display: grid;
  grid-template-columns: 220px 1fr;
  min-width: 720px;
  font-size: 0.82rem;
}

.gantt-row-label {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  color: var(--ink);
  font-weight: 600;
  display: flex;
  align-items: center;
}

.gantt-row-track {
  position: relative;
  border-bottom: 1px solid var(--border);
  padding: 8px 0;
  min-height: 36px;
}

.gantt-header-spacer {
  border-bottom: 2px solid var(--border);
}

.gantt-header-track {
  position: relative;
  border-bottom: 2px solid var(--border);
  height: 26px;
  color: var(--text-muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.gantt-header-tick {
  position: absolute;
  top: 0;
  bottom: 0;
  border-left: 1px dashed var(--border);
  padding-left: 4px;
  white-space: nowrap;
}

.gantt-bar {
  position: absolute;
  top: 8px;
  height: 20px;
  border-radius: 8px;
  background: var(--accent);
  opacity: 0.35;
  cursor: grab;
}

.gantt-bar:active {
  cursor: grabbing;
}

.gantt-bar-dragging {
  opacity: 0.7;
  box-shadow: 0 0 0 2px var(--accent-dark);
}

.gantt-bar-summary {
  background: #c98a1b;
  opacity: 0.55;
  top: 10px;
  height: 16px;
}

.gantt-milestone {
  position: absolute;
  top: 6px;
  width: 14px;
  height: 14px;
  background: var(--accent-dark);
  transform: translateX(-7px) rotate(45deg);
  cursor: grab;
}

.gantt-row-track-dependency-violated {
  background: rgba(179, 60, 60, 0.08);
}

.gantt-bar-actual {
  position: absolute;
  top: 12px;
  height: 12px;
  border-radius: 2px;
  background: var(--accent);
}

.gantt-bar-complete {
  background: var(--success);
}

.gantt-scale-toggle {
  display: flex;
  gap: 6px;
  margin-bottom: 10px;
}

@media print {
  .sidebar, .footer, .header-actions, .flash-wrap {
    display: none;
  }
}

.takeoff-page-viewer {
  position: relative;
  display: inline-block;
  margin-bottom: 1rem;
}
.takeoff-page-image {
  max-width: 100%;
  display: block;
}
.takeoff-highlight {
  position: absolute;
  border: 2px solid;
  background: rgba(255, 255, 255, 0.15);
  pointer-events: none;
}
.takeoff-highlight-beam { border-color: #d97706; background: rgba(217, 119, 6, 0.15); }
.takeoff-highlight-column { border-color: #2563eb; background: rgba(37, 99, 235, 0.15); }

/* Import loading screen (2026-08-16) -- steel-fab-themed progress display
   for the chunked import upload (chunked-import-upload.js). The bar/percent
   reflect REAL upload progress (xhr.upload.onprogress, aggregated across
   the whole file batch) -- nothing here is simulated during that phase.
   The one phase with no real progress signal, the final server-side
   classify/stage POST, switches to an indeterminate shimmer plus rotating
   status text (import-loading-fill--indeterminate) instead of faking a
   percentage. Uses only the app's existing theme tokens (--accent,
   --header-grad, --panel-alt, etc.) so it tracks the light/dark toggle
   automatically, and the whole thing degrades to a plain static bar under
   prefers-reduced-motion below. */
.import-loading {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed var(--border);
}

form.import-loading-active .form-row {
  opacity: 0.45;
  pointer-events: none;
}

.import-loading-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.import-loading-icon {
  display: inline-flex;
  color: var(--accent);
  animation: import-weld-flicker 1.6s ease-in-out infinite;
}

.import-loading-title {
  font-weight: 700;
  color: var(--ink);
  font-size: 0.92rem;
  flex: 1;
}

.import-loading-pct {
  font-family: "IBM Plex Mono", Consolas, monospace;
  font-weight: 600;
  color: var(--accent);
  font-size: 0.92rem;
  min-width: 3.2em;
  text-align: right;
}

.import-loading-track {
  position: relative;
  height: 14px;
  border-radius: 7px;
  /* Faint diagonal hazard-stripe texture in the unfilled portion --
     construction-site caution-tape read, using only existing tokens. */
  background: repeating-linear-gradient(45deg, var(--panel-alt) 0 8px, var(--bg) 8px 16px);
  border: 1px solid var(--border);
  overflow: hidden;
}

.import-loading-fill {
  position: relative;
  height: 100%;
  width: 0%;
  background: var(--header-grad);
  border-radius: 6px 0 0 6px;
  transition: width 0.25s ease-out;
}

.import-loading-fill--indeterminate {
  background-image: linear-gradient(
    90deg,
    var(--accent-dark) 0%,
    var(--accent) 25%,
    var(--accent-2) 50%,
    var(--accent) 75%,
    var(--accent-dark) 100%
  );
  background-size: 200% 100%;
  animation: import-fill-shimmer 1.4s linear infinite;
  border-radius: 6px;
}

.import-loading-spark {
  position: absolute;
  top: 50%;
  right: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff8ec 0%, var(--accent-2) 55%, transparent 75%);
  box-shadow: 0 0 6px 2px var(--accent-2);
  transform: translate(50%, -50%);
  animation: import-spark-pulse 0.9s ease-in-out infinite;
}

.import-loading-fill--indeterminate .import-loading-spark {
  display: none;
}

.import-loading-detail {
  margin: 8px 0 2px;
  font-family: "IBM Plex Mono", Consolas, monospace;
  font-size: 0.78rem;
  color: var(--text-muted);
}

.import-loading-flavor {
  margin: 2px 0 0;
  font-size: 0.82rem;
  color: var(--text);
  font-style: italic;
  min-height: 1.2em;
}

/* Retry/resume additions (2026-08-20, resilient-import redesign). A
   fatal error (retries exhausted on a batch or on /finish) reuses the
   app's existing .flash-error look rather than inventing a new palette;
   the resume banner reuses --warn tokens (a heads-up, not a failure). */
.import-loading-error-msg {
  margin-top: 10px;
}

.import-loading.import-loading-error .import-loading-icon {
  animation: none;
  color: var(--danger);
}

.import-resume-banner {
  margin-bottom: 14px;
  padding: 10px 14px;
  border-radius: 8px;
  border-left: 3px solid var(--warn);
  background: var(--warn-tint);
  color: var(--ink);
  font-size: 0.88rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.import-resume-banner p {
  margin: 0;
  flex: 1;
  min-width: 240px;
}

@keyframes import-spark-pulse {
  0%, 100% { opacity: 0.55; transform: translate(50%, -50%) scale(0.85); }
  50% { opacity: 1; transform: translate(50%, -50%) scale(1.15); }
}

@keyframes import-weld-flicker {
  0%, 100% { opacity: 1; }
  45% { opacity: 0.55; }
  50% { opacity: 1; }
  70% { opacity: 0.75; }
}

@keyframes import-fill-shimmer {
  0% { background-position: 0% 0; }
  100% { background-position: -200% 0; }
}

/* Accessibility: fall back to a plain, static progress bar. The real
   percentage/text (aria-valuenow/valuetext, the visible % and detail
   line) stay intact either way -- only the decorative motion drops. */
@media (prefers-reduced-motion: reduce) {
  .import-loading-icon,
  .import-loading-fill--indeterminate {
    animation: none;
  }
  .import-loading-fill {
    transition: none;
  }
  .import-loading-spark {
    display: none;
  }
}
.takeoff-highlight-other { border-color: #6b7280; background: rgba(107, 114, 128, 0.15); }

/* Report Builder (2026-08-17 redesign) -- reuses the same red/black
   design tokens as the rest of the app (--accent/--panel-alt/--border/
   etc.), no new palette. Goal: replace the bare stacked form + plain
   table with a scannable filter bar (chips, not form rows you read
   top-to-bottom) and a results table that reads as a real data grid,
   matching how Airtable/Linear/Tekla PowerFab present filtering. */
.rb-block {
  margin-bottom: 20px;
}

.rb-block:last-child {
  margin-bottom: 0;
}

.rb-block-label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  margin-bottom: 8px;
}

/* Data-source segmented control -- replaces a plain <select> with a row
   of tabs so switching sources is one visible click, not "open a
   dropdown to discover the options exist." */
.rb-source-tabs {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 4px;
}

.rb-source-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: 7px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.rb-source-tab input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.rb-source-tab.active {
  background: var(--panel-bg);
  color: var(--accent);
  box-shadow: var(--shadow);
}

.rb-source-desc {
  color: var(--text-muted);
  font-size: 0.82rem;
  margin: 8px 0 0;
}

/* Column picker -- toggle chips instead of a bare checkbox list, so
   "what's selected" reads at a glance instead of requiring a scan for
   checked boxes. :has() is progressive enhancement: without it every
   chip just falls back to its unchecked look plus a normal native
   checkbox, still fully usable. */
.rb-columns {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.rb-column-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 13px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel-bg);
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.rb-column-chip:hover {
  border-color: var(--steel-light);
}

.rb-column-chip:has(input:checked) {
  background: var(--accent-tint);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 700;
}

.rb-column-chip input {
  accent-color: var(--accent);
}

/* Filter bar -- the core of this redesign. Each configured filter reads
   as one compact pill-shaped row (field / operator / value inline, not
   a stacked grid section) with its own remove control; an explicit
   "+ Add Filter" affordance reveals the next one. Empty, unused filter
   slots render server-side with [hidden] so the page never shows blank
   filter rows on load -- JS only toggles visibility, it never changes
   what gets submitted. */
.rb-filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.rb-filter-row {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px 8px 6px 14px;
}

.rb-filter-row[hidden] {
  display: none;
}

.rb-filter-row select,
.rb-filter-row input {
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 0.82rem;
  font-family: inherit;
  padding: 3px 2px;
}

.rb-filter-row select:focus,
.rb-filter-row input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.rb-filter-row .rb-filter-value,
.rb-filter-row .rb-filter-value2 {
  width: 92px;
}

.rb-filter-row[data-active="1"] {
  background: var(--accent-tint);
  border-color: var(--accent);
}

.rb-filter-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,0.08);
  color: var(--text-muted);
  font-size: 0.9rem;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
}

.rb-filter-remove:hover {
  background: var(--danger);
  color: #fff;
}

.rb-add-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px dashed var(--steel-light);
  background: transparent;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.rb-add-filter-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.rb-add-filter-btn[hidden] {
  display: none;
}

.rb-run-row {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

/* Results panel */
.rb-results-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  border-bottom: 1px solid var(--border);
  padding-bottom: 10px;
  margin-bottom: 14px;
}

.rb-results-header h2 {
  border: none;
  padding: 0;
  margin: 0;
}

.rb-result-count {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-family: "IBM Plex Mono", monospace;
}

.rb-truncated-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--warn-tint);
  color: var(--warn);
  border: 1px solid var(--warn);
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 14px;
}

.rb-truncated-banner::before {
  content: '!';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--warn);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 800;
  flex-shrink: 0;
}

/* Zebra striping + header tint scoped to .rb-table specifically -- not
   applied to .data-table globally, since dozens of unrelated screens
   share that base class and a global zebra change is out of scope
   here. */
.rb-table thead th {
  background: var(--panel-alt);
}

.rb-table tbody tr:nth-child(even) td {
  background: var(--panel-alt);
}

.rb-table tbody tr:hover td {
  background: var(--accent-tint);
}

.rb-empty-state {
  text-align: center;
  padding: 34px 20px;
  border: 1px dashed var(--border);
  border-radius: 12px;
}

.rb-empty-state .empty {
  margin: 0 0 4px;
}

.rb-empty-state .subtitle {
  margin: 0;
  font-size: 0.85rem;
}

/* Saved Reports list -- small colored dot + label per data source so
   the source column scans as fast as a status badge does elsewhere in
   the app. */
.badge-source-shop_job { background: var(--accent-tint); color: var(--accent); }
.badge-source-purchase_order { background: var(--warn-tint); color: var(--warn); }
.badge-source-estimate { background: var(--success-tint); color: var(--success); }
.badge-source-customer { background: var(--success-tint); color: var(--success); }
.badge-source-vendor { background: var(--warn-tint); color: var(--warn); }
.badge-source-project { background: var(--accent-tint); color: var(--accent); }
.badge-source-subcontractor { background: var(--panel-alt); color: var(--text-muted); }

/* Reporting Center hub -- grouped report index (rebuilt 2026-08-17).
   Every report in the app is listed here under a domain heading rather
   than in one flat grid, so the page reads as one Reports product
   instead of a directory listing. */
.report-section {
  margin-bottom: 30px;
}

.report-section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 7px;
  margin-bottom: 14px;
}

.report-section-title {
  font-family: "Big Shoulders Display", sans-serif;
  font-weight: 600;
  font-size: 1.05rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0;
}

.report-section-note {
  color: var(--text-muted);
  font-size: 0.82rem;
  margin: 0;
}

.report-section .module-grid {
  margin-bottom: 0;
}

.report-section-footnote {
  margin-top: 12px;
}

/* Labor Benchmark / List of Changes have no company-wide URL -- they only
   exist per project / per shop job -- so their hub entry is a card with a
   real picker in it rather than a plain link. Same card chrome, minus the
   whole-card link affordance. */
.module-card-picker:hover {
  border-left-color: var(--accent);
  box-shadow: none;
}

.report-picker {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 8px 9px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.86rem;
  font-family: inherit;
  background: var(--panel-bg);
  color: var(--text);
}

.report-picker:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.report-picker-hint {
  display: block;
  margin-top: 8px;
  font-size: 0.76rem;
  color: var(--text-muted);
}

a.report-picker-hint {
  text-decoration: none;
}

a.report-picker-hint:hover {
  color: var(--accent);
  text-decoration: underline;
}

.report-picker-empty {
  margin-bottom: 0;
  font-style: italic;
}

/* Reporting Center hub -- small tag distinguishing the two report-
   builder tools at a glance (aggregate/chart vs. row-level/filterable),
   since both live in the same card grid with similar names. */
.module-card-tag {
  display: inline-block;
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--accent);
  background: var(--accent-tint);
  border-radius: 999px;
  padding: 2px 8px;
  margin-top: 8px;
}
