/* ===== Reset & Base ===== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 14px; color: #343333; background: #f1f2f2; line-height: 1.5; }
a { color: #3c557c; text-decoration: none; }
a:hover { text-decoration: underline; }
/* Links in running text. The brand's secondary blue sits too close to body
   text (1.7:1) to be told apart by colour alone, as the old bright blue could
   (3.3:1), so a link inside a sentence carries a teal underline. Buttons, the
   nav and linked table rows keep their own look. */
p a:not(.btn), .help-body li a {
  text-decoration: underline; text-decoration-color: #00a5b1;
  text-decoration-thickness: 2px; text-underline-offset: 2px;
}

/* ===== Navbar ===== */
/* Brand palette (guide 1.5, adopted 2026-10-15): navy chrome, teal accent,
   secondary blue for links and text. White on teal is 3.0:1, too faint for
   button text, so teal buttons carry navy (4.9:1). */
.navbar { display: flex; align-items: center; gap: 2rem; background: #002b49; color: #fff; padding: 0.75rem 1.5rem; border-bottom: 3px solid #00a5b1; }
.navbar-brand { font-size: 1.1rem; font-weight: 700; color: #fff; }
.navbar-brand:hover { text-decoration: none; color: #bdd1e4; }
.nav-links { display: flex; gap: 1rem; list-style: none; }
.nav-links a { color: #c6c7c9; font-size: 0.9rem; }
.nav-links a:hover { color: #fff; text-decoration: none; }
.navbar-toggle { display: none; } /* shown only on mobile via @media below */
.navbar-user { margin-left: auto; display: flex; align-items: center; gap: 0.75rem; }
.navbar-user-name { font-size: 0.8rem; color: #828386; text-decoration: none; }
/* The name is the way to Change password (review R-91). */
a.navbar-user-name:hover, a.navbar-user-name:focus-visible { color: #fff; text-decoration: underline; }
.navbar-user-role { color: #626366; font-size: 0.75rem; }

/* ── Nav dropdowns ── */
.nav-dropdown { position: relative; }
.nav-dropdown > a { display: flex; align-items: center; gap: 0.25rem; }
.nav-dropdown > a::after { content: "▾"; font-size: 0.65rem; opacity: 0.7; }
.nav-dropdown-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  padding-top: 0.5rem; /* visual gap without breaking hover */
  background: #002b49;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 6px;
  min-width: 170px;
  padding: 0.35rem 0;
  z-index: 200;
  box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.nav-dropdown.open .nav-dropdown-menu { display: block; }
.nav-dropdown-menu a {
  display: block;
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
  white-space: nowrap;
  color: #c6c7c9 !important;
}
.nav-dropdown-menu a:hover { background: rgba(255,255,255,0.1); color: #fff !important; }

/* ===== Layout ===== */
.main-content { max-width: 1400px; margin: 0 auto; padding: 1.5rem; }
.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
.page-header h1 { font-size: 1.5rem; font-weight: 700; color: #002b49; }
.header-actions { display: flex; gap: 0.5rem; }

/* ===== Buttons ===== */
.btn { display: inline-block; padding: 0.4rem 0.9rem; border-radius: 4px; font-size: 0.85rem; font-weight: 500; cursor: pointer; border: none; transition: background 0.15s; }
.btn-primary { background: #00a5b1; color: #002b49; font-weight: 600; }
.btn-primary:hover { background: #002b49; text-decoration: none; color: #fff; }
.btn-secondary { background: #dddedf; color: #343333; }
.btn-secondary:hover { background: #c6c7c9; text-decoration: none; color: #343333; }
.btn-danger { background: #dc2626; color: #fff; }
.btn-danger:hover { background: #b91c1c; color: #fff; text-decoration: none; }
.btn-sm { padding: 0.25rem 0.6rem; font-size: 0.8rem; }

/* ===== Tables ===== */
.data-table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 6px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.data-table th { background: #002b49; color: #fff; padding: 0.6rem 0.75rem; text-align: left; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }
.data-table td { padding: 0.55rem 0.75rem; border-bottom: 1px solid #dddedf; }
.data-table tbody tr:hover { background: #f7f8f8; }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tfoot td { background: #f1f2f2; font-weight: 600; }
.mini-table { border-collapse: collapse; font-size: 0.85rem; }
.mini-table td { padding: 0.2rem 0.5rem; }

/* ===== Cards ===== */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.stat-card { background: #fff; border-radius: 6px; padding: 1rem 1.25rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); border-top: 3px solid #00a5b1; }
.stat-card-good { border-top-color: #16a34a; }
.stat-card-fair { border-top-color: #ca8a04; }
.stat-card-poor { border-top-color: #dc2626; }
.stat-label { font-size: 0.75rem; color: #626366; text-transform: uppercase; letter-spacing: 0.05em; }
.stat-value { font-size: 1.5rem; font-weight: 700; color: #002b49; margin-top: 0.25rem; }
.benchmark-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem; }
.benchmark-card { background: #fff; border-radius: 6px; padding: 1rem 1.25rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.benchmark-card h3 { font-size: 0.8rem; font-weight: 700; color: #002b49; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
.detail-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.detail-card { background: #fff; border-radius: 6px; padding: 1rem 1.25rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.detail-card h3 { font-size: 0.85rem; font-weight: 700; color: #002b49; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
dl { display: grid; grid-template-columns: 1fr 1.5fr; gap: 0.25rem 0.75rem; }
dt { font-size: 0.8rem; color: #626366; }
dd { font-size: 0.85rem; color: #343333; }
.notes-card { background: #fff; border-radius: 6px; padding: 1rem 1.25rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 1.5rem; }
.notes-card h3 { font-size: 0.85rem; font-weight: 700; color: #002b49; margin-bottom: 0.5rem; text-transform: uppercase; }
.form-card { background: #fff; border-radius: 6px; padding: 1.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); max-width: 860px; }
.form-section { margin-bottom: 1.5rem; padding-bottom: 1.25rem; border-bottom: 1px solid #dddedf; }
.form-section:last-of-type { border-bottom: none; }
.form-section h3 { font-size: 0.85rem; font-weight: 700; color: #002b49; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.75rem; }
.form-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.25rem; }
/* Side-by-side page sections. Templates used to write this grid inline, where
   the mobile media query could not reach it and the columns stayed two-up on a
   phone. Use these classes instead of an inline grid-template-columns. */
.split-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
.split-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; }
/* A section title with its action buttons on the right. Written inline in a
   dozen templates without flex-wrap, so on a phone the buttons overlapped the
   heading instead of dropping below it. */
.section-head {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.5rem;
}

/* ===== Forms ===== */
.form-group { margin-bottom: 1rem; }
.form-group label { display: block; font-size: 0.85rem; font-weight: 600; color: #343333; margin-bottom: 0.3rem; }
.form-group input[type=text], .form-group input[type=number], .form-group input[type=date],
.form-group input[type=email], .form-group input[type=password], .form-group input[type=tel],
.form-group input[type=search], .form-group select, .form-group textarea {
  width: 100%; padding: 0.45rem 0.6rem; border: 1px solid #c6c7c9; border-radius: 4px; font-size: 0.9rem; background: #fff;
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
  outline: none; border-color: #00a5b1; box-shadow: 0 0 0 2px rgba(0,165,177,0.25);
}
/* Filter bars and toolbars mark their controls .form-control. The class was
   used in seven templates but never defined, so those inputs rendered as raw
   browser defaults beside the styled ones in .form-group. min-width:0 matters
   as much as the look: these sit in flex rows, and a select's automatic
   minimum is the width of its longest <option>, which beat its flex-basis and
   pushed the estimate-item filter bar 80px past the edge of a phone. */
.form-control {
  padding: 0.45rem 0.6rem; border: 1px solid #c6c7c9; border-radius: 4px;
  font-size: 0.9rem; background: #fff; min-width: 0; max-width: 100%;
}
.form-control:focus {
  outline: none; border-color: #00a5b1; box-shadow: 0 0 0 2px rgba(0,165,177,0.25);
}
.has-error input, .has-error select, .has-error textarea { border-color: #dc2626; }
.field-help { font-size: 0.78rem; color: #626366; margin-top: 0.2rem; }
.error-msg { display: block; color: #dc2626; font-size: 0.8rem; margin-top: 0.2rem; }
.help-text { font-size: 0.8rem; color: #626366; }
.form-actions { display: flex; gap: 0.75rem; margin-top: 1.25rem; }

/* ===== Badges ===== */
.badge { display: inline-block; padding: 0.2rem 0.6rem; border-radius: 4px; font-size: 0.75rem; font-weight: 600; }
.badge-new  { background: #eef3f8; color: #002b49; }
.badge-good { background: #dcfce7; color: #166534; }
.badge-fair { background: #fef9c3; color: #854d0e; }
.badge-poor { background: #fee2e2; color: #991b1b; }
.badge-secondary { background: #dddedf; color: #4d4e50; }
.badge-neutral { background: #dddedf; color: #4d4e50; }
/* A score nobody looked at on that date (carried, adjusted, from completed
   work, the as-built 100s) keeps its colour but loses its fill (review R-56). */
.badge.badge-derived { background: #fff; box-shadow: inset 0 0 0 1.5px currentColor; font-style: italic; }
.source-mark { display: inline-block; width: 0.6em; height: 0.6em; border-radius: 50%; border: 1.5px solid currentColor;
               margin-right: 0.3em; vertical-align: 0.02em; box-sizing: border-box; }
.source-observed { background: currentColor; }
.source-repair { background: linear-gradient(90deg, currentColor 50%, transparent 50%); }
.rating-source-legend { display: flex; flex-wrap: wrap; gap: 0.35rem 1.25rem; font-size: 0.8rem; color: #626366; margin: -0.25rem 0 0.75rem; }
.history-system-head { white-space: normal; min-width: 5rem; line-height: 1.2; }
.condition-summary { display: flex; gap: 0.75rem; margin-bottom: 1.5rem; }
.condition-display { display: inline-block; padding: 0.5rem 1rem; border-radius: 6px; font-size: 1.1rem; font-weight: 700; }
.score { font-size: 0.85rem; font-weight: 400; margin-left: 0.5rem; }

/* ===== Estimate Editor ===== */
.estimate-editor input[type=text], .estimate-editor input[type=number] {
  width: 100%; padding: 0.3rem 0.4rem; border: 1px solid #c6c7c9; border-radius: 3px; font-size: 0.82rem;
}
.estimate-editor select { width: 100%; padding: 0.3rem; border: 1px solid #c6c7c9; border-radius: 3px; font-size: 0.82rem; }
.item-name-input { min-width: 180px; }
/* Widths that keep the figures readable at laptop width: at 1024px Unit
   Price read "7.!" and the repair pickers one or two characters (R-98). */
.estimate-editor th, .estimate-editor td { padding: 0.45rem 0.3rem; }
.estimate-editor .item-name-input { min-width: 9rem; }
/* The work item sits above the name in the same cell, so the row keeps its
   eleven columns (R-98). */
.work-item-input { display: block; width: 6rem; margin-bottom: 0.25rem; font-size: 0.8rem; }
.estimate-editor .qty-input, .estimate-editor .price-input { width: 11ch; min-width: 11ch; -moz-appearance: textfield; appearance: textfield; }
/* Nobody steps a quantity of 1250 by 0.01; the spinner only ate the width the digits needed. */
.estimate-editor .qty-input::-webkit-inner-spin-button, .estimate-editor .qty-input::-webkit-outer-spin-button,
.estimate-editor .price-input::-webkit-inner-spin-button, .estimate-editor .price-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.estimate-editor .unit-select { min-width: 4.25rem; }
.estimate-editor .year-input { width: 4rem; text-align: center; }
.estimate-editor .repair-subtype-select { min-width: 9.75rem; }
.estimate-editor .where-cell { min-width: 9.5rem; }
.estimate-editor .repair-type-name { font-size: 0.72rem; color: #626366; margin-top: 0.2rem; max-width: 11rem; line-height: 1.25; }
.row-menu-items .notes-toggle-btn { opacity: 1; }
.estimate-editor .where-cell .mini-label {
  display: block; font-size: 0.68rem; color: #626366; text-transform: uppercase; letter-spacing: 0.02em;
}
.estimate-editor .where-cell .mini-label + .mini-label { margin-top: 0.3rem; }
.estimate-editor .where-cell .mini-label input, .estimate-editor .where-cell .mini-label select {
  display: block; margin-top: 0.1rem; text-transform: none; letter-spacing: 0; color: #343333;
}
.estimate-editor .select-cell { text-align: center; width: 2rem; }
.row-menu { position: relative; display: inline-block; }
.row-menu > summary { list-style: none; cursor: pointer; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu-items {
  position: absolute; right: 0; z-index: 50; display: flex; flex-direction: column; gap: 0.25rem;
  background: #fff; border: 1px solid #dddedf; border-radius: 6px; padding: 0.35rem;
  box-shadow: 0 4px 12px rgba(0,0,0,0.12); min-width: 7.5rem;
}
.row-menu-items .btn { justify-content: flex-start; }
.notes-toggle-btn { opacity: 0.45; }
.notes-toggle-btn.has-notes { opacity: 1; background: #dee8f1; border-color: #bdd1e4; color: #002b49; }
.estimate-notes-row td { background: #f7f8f8; }
.line-total { font-weight: 600; white-space: nowrap; }
.row-actions { white-space: nowrap; }
.editor-actions { margin-top: 1rem; }
.autocomplete-results { position: absolute; z-index: 100; background: #fff; border: 1px solid #c6c7c9; border-radius: 4px; max-height: 200px; overflow-y: auto; }
.autocomplete-results div { padding: 0.4rem 0.6rem; cursor: pointer; font-size: 0.85rem; }
.autocomplete-results div:hover { background: #f1f2f2; }

/* ===== Ratings Table ===== */
.ratings-table .notes-field { width: 100%; padding: 0.25rem; border: 1px solid #c6c7c9; border-radius: 3px; }

/* ===== Messages ===== */
.messages { margin-bottom: 1rem; }
.message { padding: 0.6rem 1rem; border-radius: 4px; margin-bottom: 0.5rem; font-size: 0.9rem; }
.message-success { background: #dcfce7; color: #166534; }
.message-error { background: #fee2e2; color: #991b1b; }
.message-warning { background: #fef9c3; color: #854d0e; }
.message-info { background: #dee8f1; color: #002b49; }

/* ===== Resolve screen ===== */
.resolve-intro { color: #4d4e50; margin-bottom: 1.5rem; max-width: 700px; }
.resolve-section { margin-bottom: 2rem; }
.resolve-section h2 { font-size: 1rem; font-weight: 700; color: #002b49; margin-bottom: 0.75rem; border-bottom: 2px solid #dddedf; padding-bottom: 0.4rem; }
.resolve-row { background: #fff; border-radius: 6px; padding: 0.9rem 1rem; margin-bottom: 0.75rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
.resolve-raw { font-family: monospace; font-size: 0.9rem; font-weight: 700; color: #002b49; margin-bottom: 0.6rem; }
.resolve-context { font-family: sans-serif; font-size: 0.75rem; font-weight: 400; color: #626366; margin-left: 0.5rem; }
.resolve-options { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.resolve-option { display: flex; align-items: center; gap: 0.4rem; padding: 0.35rem 0.75rem; border: 1px solid #c6c7c9; border-radius: 4px; cursor: pointer; background: #f7f8f8; font-size: 0.85rem; }
.resolve-option:has(input:checked) { background: #dee8f1; border-color: #3c557c; }
.resolve-option input { cursor: pointer; }
.resolve-skip { color: #626366; }
.resolve-match { color: #343333; }
.resolve-type-hint { color: #626366; font-size: 0.78rem; }
.resolve-score { display: inline-block; background: #dcfce7; color: #166534; font-size: 0.72rem; font-weight: 600; padding: 0.1rem 0.4rem; border-radius: 10px; margin-left: 0.3rem; }
.resolve-no-suggestions { font-size: 0.82rem; color: #828386; font-style: italic; }

/* ===== Preview inline overrides ===== */
.preview-override-type, .preview-override-subtype { font-size: 0.8rem; padding: 0.25rem 0.4rem; border: 1px solid #f97316; border-radius: 3px; background: #fff7ed; width: 100%; }
.alias-checkbox-label { display: block; font-size: 0.75rem; color: #626366; margin-top: 0.3rem; white-space: nowrap; cursor: pointer; }
.alias-checkbox-label input { margin-right: 0.3rem; }

/* ===== Preview ===== */
.row-error { background: #fff5f5 !important; }
.table-scroll { overflow-x: auto; margin-bottom: 1.5rem; }
.preview-table th, .preview-table td { font-size: 0.8rem; }

/* ===== Column alignment ===== */
.align-left { text-align: left; }
.align-right { text-align: right; white-space: nowrap; }
.data-table th.align-right { text-align: right; }

/* ===== Estimate column widths ===== */
col.col-item { width: 30%; }
col.col-qty  { width: 6%; }
col.col-unit { width: 5%; }
col.col-phase { width: 10%; }
col.col-total { width: 10%; }

/* ===== Estimate Groups ===== */
.estimate-group { margin-bottom: 1.5rem; }
.estimate-group-header { display: flex; justify-content: space-between; align-items: center; background: #002b49; color: #fff; padding: 0.5rem 0.75rem; border-radius: 4px 4px 0 0; }
.estimate-group-title { font-weight: 700; font-size: 0.9rem; }
.estimate-group-total { font-weight: 700; font-size: 0.9rem; }
.estimate-group .data-table { border-radius: 0 0 4px 4px; }
.estimate-group .data-table th { background: #3c557c; }
.estimate-grand-total { display: flex; justify-content: space-between; align-items: center; background: #002b49; color: #fff; padding: 0.6rem 0.75rem; border-radius: 4px; font-weight: 700; font-size: 1rem; margin-top: 0.5rem; }
.location-badge { display: inline-block; background: #dee8f1; color: #002b49; padding: 0.1rem 0.5rem; border-radius: 10px; font-size: 0.75rem; font-weight: 600; }
.row-immediate { background: #fff5f5 !important; }
.col-immediate { background: #fff5f5; color: #991b1b; }
.data-table th.col-immediate { background: #b91c1c; color: #fff; }
.subtotal-row td { background: #f1f2f2; border-top: 2px solid #c6c7c9; }
.grand-total-table { margin-top: 0.25rem; }
.grand-total-row td { background: #002b49; color: #fff; font-weight: 700; font-size: 0.9rem; padding: 0.6rem 0.75rem; }

/* ===== Responsive ===== */
/* ===== Checkbox size — apply globally so compare checkboxes are usable ===== */
input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; }

/* ===== Portfolio mobile cards ===== */
.portfolio-cards { display: none; }
.portfolio-card {
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  padding: 0.9rem 1rem;
  margin-bottom: 0.75rem;
  border-left: 4px solid #002b49;
}
.portfolio-card.rr-flag { border-left-color: #dc2626; background: #fff5f5; }
.portfolio-card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; }
.portfolio-card-name { font-weight: 700; font-size: 1rem; color: #002b49; }
.portfolio-card-rank { font-size: 0.75rem; color: #828386; margin-top: 0.15rem; }
.portfolio-card-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem 1rem; font-size: 0.82rem; }
.portfolio-card-metric dt { color: #626366; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; margin-top: 0.3rem; }
.portfolio-card-metric dd { font-weight: 600; color: #343333; margin: 0; }
.portfolio-card-footer { margin-top: 0.65rem; display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* ===== Ratings card grid (replaces table on all sizes, 2-col on desktop) ===== */
.ratings-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; margin-bottom: 1rem; }
.rating-card { background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); padding: 1rem 1.1rem; }
.rating-card-title { font-weight: 700; font-size: 0.9rem; color: #002b49; margin-bottom: 0.75rem; padding-bottom: 0.4rem; border-bottom: 1px solid #dddedf; }
.rating-card label { display: block; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: #626366; margin: 0.6rem 0 0.3rem; }
.rating-card select, .rating-card input[type="text"], .rating-card input[type="number"] { width: 100%; padding: 0.4rem 0.5rem; border: 1px solid #c6c7c9; border-radius: 4px; font-size: 0.9rem; }
.score-input { font-weight: 600; text-align: center; }
.rating-btn-group { display: flex; gap: 0.4rem; }
.rating-btn { flex: 1; min-height: 44px; border: 2px solid #dddedf; background: #fff; border-radius: 4px; font-size: 0.82rem; font-weight: 600; cursor: pointer; transition: all 0.1s; color: #343333; }
.rating-btn:hover { border-color: #828386; }
.rating-btn.active-new   { background: #eef3f8; border-color: #00a5b1; color: #002b49; }
.rating-btn.active-good  { background: #dcfce7; border-color: #16a34a; color: #15803d; }
.rating-btn.active-fair  { background: #fef9c3; border-color: #ca8a04; color: #a16207; }
.rating-btn.active-poor  { background: #fee2e2; border-color: #dc2626; color: #b91c1c; }
.rating-concern-row { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.5rem; font-size: 0.85rem; color: #343333; }
.rating-concern-row input[type="checkbox"] { margin: 0; }
.clear-rating-btn { padding: 0.35rem 0.6rem; }

/* ===== Field Survey capture (mobile-first by design, not a retrofit) ===== */
.field-survey-level-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 0.85rem; }
.field-survey-level-card {
  display: block; background: #fff; border: 1px solid #dddedf; border-radius: 10px;
  padding: 1.25rem 1rem; text-align: center; text-decoration: none; color: inherit;
  box-shadow: 0 1px 3px rgba(0,0,0,0.08); min-height: 72px;
}
.field-survey-level-name { font-weight: 700; font-size: 1.05rem; color: #002b49; }
.field-survey-level-count { font-size: 0.78rem; color: #626366; margin-top: 0.3rem; }

/* Survey wizard steps number themselves. The cards are conditional — Major
   System Ratings only renders for a parking structure — so hardcoded numbers
   went stale the moment a card was added or removed, which is how the page
   ended up reading 1, 2, 4, 5, 6. */
.field-survey-steps { counter-reset: survey-step; }
.field-survey-steps .field-survey-level-card { counter-increment: survey-step; }
.field-survey-steps .field-survey-level-name::before {
  content: counter(survey-step) ". ";
}

/* Observation-only is a checkbox plus its words, tapped as one unit. */
.obs-only-label {
  display: flex; align-items: center; gap: 0.5rem; cursor: pointer;
  font-size: 0.8rem; color: #4d4e50;
}
.obs-only-label .obs-only-text { display: none; }

/* Table-style capture (estimate-editor pattern, reused): a persistent blank
   row at the top plus committed rows, newest first. See survey_capture.html. */
.field-survey-table input[type=text], .field-survey-table input[type=number],
.field-survey-table select {
  width: 100%; padding: 0.3rem; border: 1px solid #c6c7c9; border-radius: 3px; font-size: 0.82rem;
}
.field-survey-table .new-element-fields, .field-survey-table .new-item-name-input {
  margin-top: 0.3rem;
}
.field-survey-table .new-element-fields select, .field-survey-table .new-element-fields input {
  margin-bottom: 0.25rem;
}
.field-obs-stepper { display: flex; align-items: center; gap: 0.3rem; }
.field-obs-stepper-btn {
  flex: 0 0 auto; width: 32px; min-height: 32px; border: 1px solid #c6c7c9; border-radius: 4px;
  background: #f7f8f8; font-size: 1.1rem; line-height: 1; cursor: pointer; color: #343333;
}
.field-obs-stepper-btn:active { background: #dddedf; }
.field-obs-stepper-value { text-align: center; flex: 1 1 auto; min-width: 3.5rem; }

/* Stacked cells: two related fields on two lines within one narrower column,
   instead of every field getting its own full-width column (keeps the table
   from sprawling horizontally). Real <label> elements, not the data-label
   pseudo-content trick, since each cell holds more than one field. */
.field-survey-table .stacked-cell .mini-label {
  display: block; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.03em;
  color: #828386; margin: 0.35rem 0 0.15rem;
}
.field-survey-table .stacked-cell .mini-label:first-child { margin-top: 0; }
.field-survey-table .stacked-cell::before { content: none; }

.field-survey-table tr.observation-only .reference-item-select,
.field-survey-table tr.observation-only .new-item-name-input,
.field-survey-table tr.observation-only .new-item-name-label,
.field-survey-table tr.observation-only .unit-select,
.field-survey-table tr.observation-only .field-obs-stepper {
  opacity: 0.4;
}
.field-obs-notes-row .notes-textarea {
  /* font-family: a textarea does not inherit it, and fell back to monospace. */
  width: 100%; min-height: 3rem; font-size: 1rem; font-family: inherit; resize: vertical;
  border: 1px solid #c6c7c9; border-radius: 4px; padding: 0.4rem 0.5rem;
}
.field-obs-notes-row td, .field-obs-photos-row td { background: #f7f8f8; padding: 0.25rem 0.5rem 0.5rem; }


/* ===== Analytics ===== */
.analytics-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 0.5rem; }
.analytics-card { background: #fff; border-radius: 6px; padding: 1rem 1.25rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.analytics-card h3 { font-size: 0.85rem; font-weight: 700; color: #002b49; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
.analytics-card-wide { grid-column: span 2; }

h2 { font-size: 1.1rem; font-weight: 700; color: #002b49; margin: 1.5rem 0 0.75rem; }
h3 { font-size: 0.95rem; }
h4 { font-size: 0.85rem; font-weight: 600; margin: 0.75rem 0 0.4rem; }

/* ===== Portfolio Tabs ===== */
.tab-nav { display: flex; gap: 0; flex-wrap: wrap; }
.tab-btn {
  padding: 0.55rem 1.1rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: #626366;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
  margin-bottom: -2px;
}
.tab-btn:hover { color: #002b49; }
.tab-btn.active { color: #002b49; border-bottom-color: #00a5b1; }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* ===== Attachments ===== */
.attachment-panel { margin-top: 0.5rem; }
.attachment-panel h3 { font-size: 0.95rem; }

.attachment-item {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  margin: 0.4rem 0.5rem 0.4rem 0;
  vertical-align: top;
  max-width: 120px;
}
.attachment-thumb {
  width: 110px;
  height: 80px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid #dddedf;
}
.attachment-thumb-link { display: block; }
.attachment-file-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0.5rem;
  border: 1px solid #dddedf;
  border-radius: 4px;
  background: #f7f8f8;
  text-decoration: none;
  color: #343333;
  width: 110px;
  min-height: 60px;
  justify-content: center;
}
.attachment-icon { font-size: 1.5rem; }
.attachment-filename {
  font-size: 0.7rem;
  color: #626366;
  word-break: break-all;
  text-align: center;
  margin-top: 0.2rem;
}
.attachment-caption {
  font-size: 0.72rem;
  color: #626366;
  text-align: center;
  margin-top: 0.2rem;
  max-width: 110px;
  word-break: break-word;
}
.attachment-delete {
  position: absolute;
  top: -6px;
  right: -6px;
  background: #dc2626;
  color: #fff;
  border: none;
  border-radius: 50%;
  width: 24px;
  height: 24px;
  font-size: 0.75rem;
  line-height: 24px;
  text-align: center;
  cursor: pointer;
  padding: 0;
  opacity: 0.85;
}
.attachment-delete:hover, .attachment-delete:focus { opacity: 1; }
.attachment-empty { font-size: 0.85rem; color: #828386; margin: 0.25rem 0 0.5rem; }

/* ===== Data Explorer ===== */
.explorer-filters {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.85rem;
  background: #fff; border: 1px solid #dddedf; border-radius: 8px;
  padding: 0.85rem 1rem; margin-bottom: 1rem;
}
.explorer-filters .form-group { margin: 0; min-width: 150px; }
.explorer-filters .form-group label {
  display: block; font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.04em; color: #626366; margin-bottom: 0.25rem;
}
.explorer-filters .form-group.narrow { min-width: 100px; }
.explorer-match-count { margin-left: auto; font-size: 0.82rem; color: #626366; white-space: nowrap; }
.explorer-match-count strong { color: #002b49; }

.explorer-lens-nav { border-bottom: 2px solid #dddedf; margin-bottom: 0.5rem; }

.explorer-caption {
  font-size: 0.82rem; color: #626366; margin: 0.6rem 0 1rem; max-width: 75ch;
}

.explorer-lens { margin-bottom: 2rem; }

.explorer-chart-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 1rem; margin-bottom: 1.25rem;
}
.explorer-chart-card {
  background: #fff; border: 1px solid #dddedf; border-radius: 8px; padding: 1rem 1.1rem;
}
.explorer-chart-card h3 {
  font-size: 0.8rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  color: #626366; margin: 0 0 0.65rem;
}
.explorer-chart-card-wide { grid-column: 1 / -1; }
.explorer-chart-wrap { position: relative; height: 280px; }

.explorer-inline-filter {
  display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem;
}
.explorer-inline-filter label { font-size: 0.82rem; font-weight: 600; color: #4d4e50; }

.explorer-table-wrap { overflow-x: auto; }

.explorer-heatmap-wrap { overflow-x: auto; }
table.explorer-heatmap { border-collapse: collapse; font-size: 0.76rem; white-space: nowrap; }
table.explorer-heatmap th, table.explorer-heatmap td {
  padding: 0.35rem 0.55rem; text-align: center; border: 1px solid #fff;
}
table.explorer-heatmap thead th {
  background: #002b49; color: #fff; font-weight: 600; writing-mode: vertical-rl;
  transform: rotate(180deg); text-align: left; padding: 0.5rem 0.4rem; max-height: 140px;
  position: sticky; top: 0; z-index: 2;
}
table.explorer-heatmap thead th:first-child {
  writing-mode: horizontal-tb; transform: none; left: 0; z-index: 3;
}
table.explorer-heatmap tbody th {
  text-align: left; background: #f7f8f8; font-weight: 600; color: #002b49;
  position: sticky; left: 0; z-index: 1; writing-mode: horizontal-tb; white-space: nowrap;
}
table.explorer-heatmap td.no-data { background: #f1f2f2; color: #c6c7c9; }
table.explorer-heatmap td a { color: inherit; text-decoration: none; }

/* ===== Mobile =====
   Everything phone-sized lives here, and it has to stay at the END of this
   file. Most of these rules match a desktop rule's specificity exactly, so
   they win on source order alone. While this block sat mid-file the
   Analytics section below it quietly re-applied `grid-template-columns:
   1fr 1fr` and `grid-column: span 2`, and every assessment-detail card
   stayed two-up on a 375px screen. */
/* ===== Home page (dashboard) =====
   Classes rather than inline styles, so the phone layout below can adjust
   them; the old dashboard was all inline style and hover scripts. */
.nav-search { display: flex; align-items: center; margin-left: auto; margin-right: -1rem; }
.navbar-user .btn { white-space: nowrap; }
.nav-search input { width: 220px; height: 34px; padding: 0 0.75rem; border: 0; border-radius: 6px; font-size: 0.9rem; }
.home-greeting h1 { margin: 0; font-size: 1.7rem; color: #002b49; }
.home-greeting p { margin: 0.2rem 0 0; color: #4d4e50; }
.home-tasks { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0.75rem; margin: 1.25rem 0 1.5rem; }
.home-task { display: flex; gap: 0.75rem; align-items: flex-start; background: #fff; border: 1px solid #dddedf; border-radius: 10px; padding: 0.85rem 1rem; color: #343333; text-decoration: none; }
.home-task:hover { border-color: #002b49; text-decoration: none; }
.home-task strong { display: block; color: #002b49; }
.home-task small { font-size: 0.85rem; color: #4d4e50; }
.home-task svg { flex: none; margin-top: 2px; }
.home-card { background: #fff; border: 1px solid #dddedf; border-radius: 10px; padding: 1rem 1.25rem; }
.home-card h2 { margin: 0 0 0.75rem; font-size: 1.1rem; color: #002b49; }
.home-section-label { margin: 0 0 0.6rem; font-size: 0.8rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: #4d4e50; }
.home-section-label span { text-transform: none; letter-spacing: 0; font-weight: 400; }
.home-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0.75rem; margin-bottom: 1.5rem; }
.home-tile { display: block; background: #fff; border: 1px solid #dddedf; border-radius: 10px; padding: 0.85rem 1rem; min-height: 88px; color: #343333; text-decoration: none; }
.home-tile:hover { border-color: #002b49; text-decoration: none; }
.home-tile.is-active { border: 2px solid #00a5b1; background: #eef3f8; }
.home-tile .n { display: block; font-size: 2rem; font-weight: 700; line-height: 1.1; color: #002b49; }
.home-tile.is-urgent .n { color: #b91c1c; }
.home-pair { display: flex; flex-wrap: wrap; gap: 1.25rem; margin-bottom: 1.5rem; }
.home-pair > .wide { flex: 999 1 520px; min-width: 0; }
.home-pair > .narrow { flex: 1 1 300px; min-width: 0; }
.home-list { list-style: none; margin: 0; padding: 0; }
.home-list li { display: flex; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; padding: 0.65rem 0; border-bottom: 1px solid #f1f2f2; }
.home-list li:last-child { border-bottom: 0; }
.home-list .sub { display: block; font-size: 0.85rem; color: #4d4e50; }
.home-list .act { font-size: 0.85rem; font-weight: 600; color: #92400e; }
.home-list .act.urgent { color: #b91c1c; }
.home-empty { color: #4d4e50; font-size: 0.9rem; margin: 0; }
.home-progress { height: 6px; background: #dddedf; border-radius: 3px; margin: 0.6rem 0 0.9rem; }
.home-progress div { height: 6px; background: #00a5b1; border-radius: 3px; }
.home-steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0.6rem; }
.home-steps li { display: flex; gap: 0.6rem; align-items: center; }
.home-steps .dot { width: 22px; height: 22px; border-radius: 11px; border: 2px solid #828386; box-sizing: border-box; flex: none; }
.home-steps .done .dot { background: #00a5b1; border-color: #00a5b1; }
.home-steps .done span:last-child { color: #4d4e50; text-decoration: line-through; }
.home-toolbar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; }
.home-toolbar form { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }
.home-segment { display: inline-flex; border: 1px solid #b4b5b7; border-radius: 8px; overflow: hidden; }
.home-segment a { padding: 0.45rem 0.85rem; color: #343333; text-decoration: none; font-size: 0.9rem; }
.home-segment a.is-on { background: #002b49; color: #fff; font-weight: 600; }
.home-pill { display: inline-block; padding: 0.15rem 0.6rem; border-radius: 12px; font-size: 0.78rem; font-weight: 700; }
.home-pill.urgent { background: #fde8e8; color: #991b1b; }
.home-pill.watch { background: #fdf1dc; color: #7c3a06; }
.home-clients th a { color: inherit; text-decoration: none; }
.home-clients abbr { text-decoration: underline dotted; cursor: help; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.estimate-notes { margin: 1rem 0 1.5rem; max-width: 80ch; }
.estimate-notes h3 { font-size: 0.95rem; color: #002b49; margin: 0 0 0.35rem; }
.estimate-notes ol { margin: 0 0 0.5rem; padding-left: 1.4rem; font-size: 0.87rem; color: #343333; }
.estimate-notes summary { cursor: pointer; color: #3c557c; font-size: 0.85rem; }
.estimate-notes form { margin-top: 0.5rem; display: grid; gap: 0.5rem; justify-items: start; }
.estimate-notes textarea { width: 100%; font: inherit; font-size: 0.87rem; }
.estimate-notes-help { font-size: 0.8rem; color: #626366; margin: 0; }
/* A refused row save, said in the row (estimate_row.html). */
.row-errors { margin-top: 0.25rem; font-size: 0.78rem; color: #b91c1c; }

/* Field measurement capture (actuals/_field_measurement_fields.html): sized for
   a thumb on site — big inputs, the computed quantity in large type. */
.fm-card { max-width: 640px; }
.fm-grid .fm-wide { grid-column: 1 / -1; }
.fm-dims { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 0 0.75rem; }
.fm-card input, .fm-card select { font-size: 1rem; min-height: 2.6rem; }
.fm-result { font-size: 1.35rem; font-weight: 700; color: #002b49; min-height: 1.8rem; margin: 0.25rem 0 0.75rem; }
.fm-save { min-height: 3rem; font-size: 1.05rem; }
/* Measurements kept on the device for want of signal (js/fm_queue.js). */
.fm-queue { background: #fff7ed; border: 1px solid #ff893e; border-radius: 6px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; font-size: 0.88rem; }
.fm-queue[hidden] { display: none; }
.fm-queue-refused { color: #b91c1c; }
.fm-queue-list { list-style: none; padding: 0 !important; display: grid; gap: 0.5rem; }
.fm-queue-list li { background: #fff; border-radius: 4px; padding: 0.4rem 0.6rem; }
.fm-queue-list small { display: block; color: #b91c1c; margin: 0.15rem 0 0.35rem; }
.fm-queue-list div:last-child { display: flex; gap: 0.4rem; flex-wrap: wrap; }
/* "Make available offline" (js/offline.js). */
.ol-bar { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin: 0 0 0.75rem; font-size: 0.85rem; color: #343333; }
.ol-bar[hidden] { display: none; }
.ol-bar.ol-offline { background: #002b49; color: #fff; border-radius: 6px; padding: 0.55rem 0.8rem; }
.ol-status { flex: 1 1 16rem; }
.fm-queue p { margin: 0 0 0.3rem; }
.fm-queue ul { margin: 0 0 0.5rem; padding-left: 1.2rem; color: #343333; }
/* Field reports (templates/fieldreports/). */
.fr-card { background: #fff; border-radius: 6px; padding: 1rem 1.25rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); margin-bottom: 1rem; }
.fr-card h2 { margin-top: 0; font-size: 1.1rem; }
.fr-dl { display: grid; grid-template-columns: max-content 1fr; gap: 0.3rem 1rem; margin: 0; }
.fr-dl dt { color: #626366; }
.fr-dl dd { margin: 0; }
.fr-output { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0; }
.fr-output label { font-size: 0.85rem; color: #626366; display: flex; gap: 0.3rem; align-items: center; white-space: nowrap; }
.fr-add-contact { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; margin: 0.75rem 0; font-size: 0.85rem; }
.fr-section { color: #00a5b1; margin: 1.25rem 0 0.25rem; display: flex; justify-content: space-between; gap: 1rem; }
.fr-photos-ref { color: #626366; font-size: 0.8rem; font-weight: 400; }
.fr-wi { margin: 0 0 0.5rem; font-size: 0.88rem; color: #343333; }
.fr-entry { border-left: 4px solid #dddedf; padding: 0.5rem 0.75rem; margin: 0.5rem 0 0.75rem; background: #fafafa; border-radius: 0 4px 4px 0; }
.fr-entry.status-open { border-left-color: #ff893e; }
.fr-entry.status-closed { border-left-color: #00a5b1; }
.fr-entry header { display: flex; gap: 0.5rem; align-items: baseline; flex-wrap: wrap; }
.fr-entry footer { display: flex; gap: 0.5rem; margin-top: 0.4rem; }
.fr-meta { font-size: 0.8rem; color: #626366; }
.fr-previous { font-size: 0.82rem; color: #626366; margin: 0.35rem 0; }
.fr-notes p { margin: 0.35rem 0; }
.fr-empty { color: #b45309; font-size: 0.85rem; }
.fr-radios ul, .fr-checks ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.3rem; }
.fr-radios label, .fr-checks label { font-weight: 400; display: flex; gap: 0.4rem; align-items: center; }
.fr-checks ul { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
/* Outstanding assessment items on a repair project, closed by default. */
.outstanding-items > summary { cursor: pointer; padding: 0.5rem 0; list-style-position: outside; }
.outstanding-items[open] > summary { margin-bottom: 0.5rem; }
.fm-photos { display: flex; gap: 0.5rem; flex-wrap: wrap; margin: 0.5rem 0; }
.fm-photos img { width: 96px; height: 72px; object-fit: cover; border-radius: 4px; }
/* As-Built column on the project page: a carried bid reads quieter than a
   measured figure. */
.ab-carried { color: #828386; }
.ab-carried small, .ab-measured small { display: block; font-size: 0.72rem; }
.ab-var { font-size: 0.72rem; font-weight: 600; margin-left: 0.25rem; }
.ab-var.up { color: #b45309; }
.ab-var.down { color: #3c557c; }
/* As-Built tab: progress figures, the Estimated at Completion table and its
   charts (actuals/_measurements_tab.html). Over the bid reads amber, under it
   blue: neither is a condition, so neither borrows red or green. */
.ab-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 0.75rem; margin-bottom: 1rem; }
.ab-stats > div { background: #fff; border-radius: 6px; padding: 0.75rem 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
.ab-stats span { display: block; font-size: 0.75rem; color: #626366; text-transform: uppercase; letter-spacing: 0.03em; }
.ab-stats strong { display: block; font-size: 1.3rem; color: #002b49; margin: 0.15rem 0; }
.ab-stats small { font-size: 0.78rem; color: #626366; }
.ab-over, .ab-stats small.ab-over { color: #b45309; }
.ab-under, .ab-stats small.ab-under { color: #3c557c; }
.ab-progress .eac-input { width: 7rem; text-align: right; }
.ab-progress .eac-input.revised { border-color: #002b49; font-weight: 600; }
.ab-charts { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem; }
.ab-charts .chart-card { background: #fff; border-radius: 6px; padding: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); min-width: 0; }
.ab-charts h4 { margin: 0 0 0.5rem; color: #002b49; font-size: 0.9rem; }
.ab-charts .chart-note { font-size: 0.78rem; color: #626366; margin: 0.4rem 0 0; }
/* Plan Sheets tab and sheet linking (actuals/_sheets_tab.html,
   drawing_set_link.html). */
.ps-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem; margin-bottom: 1rem; }
.ps-card { display: flex; flex-direction: column; gap: 0.15rem; background: #fff; border-radius: 6px; padding: 0.6rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); color: #343333; text-decoration: none; font-size: 0.82rem; }
.ps-card:hover { box-shadow: 0 0 0 2px #00a5b1; }
.ps-card img { width: 100%; aspect-ratio: 3 / 2; object-fit: contain; background: #f1f2f2; border-radius: 4px; margin-bottom: 0.3rem; }
.ps-card strong { color: #002b49; font-size: 0.9rem; }
.ps-upload { margin-top: 1.5rem; background: #fff; border-radius: 6px; padding: 1rem 1.25rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); max-width: 860px; }
.ps-upload h3 { margin-top: 0; }
.ps-link-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 0.75rem; margin-bottom: 1rem; }
.ps-link { background: #fff; border-radius: 6px; padding: 0.6rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); border: 2px solid transparent; }
.ps-link.linked { border-color: #00a5b1; }
.ps-link img { width: 100%; aspect-ratio: 3 / 2; object-fit: contain; background: #f1f2f2; border-radius: 4px; }
.ps-link-fields { display: grid; gap: 0.35rem; margin-top: 0.4rem; font-size: 0.82rem; }
.ps-link-fields label { display: grid; gap: 0.15rem; color: #626366; }
/* The plan view (actuals/plan_view.html, js/plan_view.js). Markers keep one
   on-screen size at every zoom, and sit centred on the point tapped. */
/* Measurements | Observations switch, and an observation's number beside
   its marker (actuals/plan_view.html). */
.pv-modes { display: inline-flex; border: 1px solid #c6c7c9; border-radius: 6px; overflow: hidden; margin-bottom: 0.6rem; }
.pv-modes a { padding: 0.4rem 0.9rem; font-size: 0.85rem; color: #343333; text-decoration: none; background: #fff; }
.pv-modes a.active { background: #002b49; color: #fff; }
.pv-marker.pv-obs b { position: absolute; left: 24px; top: -8px; font-size: 10px; font-weight: 700; color: #002b49; background: rgba(255,255,255,0.9); padding: 0 3px; border-radius: 3px; line-height: 1.4; }
.pv-toolbar { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.75rem; }
.pv-sheet-pick select { min-width: 14rem; min-height: 2.4rem; }
.pv-zoom { display: flex; gap: 0.25rem; }
.pv-place[aria-pressed="true"] { background: #ff893e; border-color: #ff893e; color: #002b49; }
.pv-status { font-size: 0.85rem; color: #343333; }
.pv-hint { font-size: 0.8rem; color: #626366; margin: 0 0 0.5rem; }
.pv-layout { display: grid; grid-template-columns: minmax(0, 1fr) 270px; gap: 1rem; align-items: start; }
.pv-detail[hidden], .pv-marker[hidden], .pv-pending[hidden] { display: none; }
/* A maximum, not a height: at Fit the box is the sheet's own height, so a
   phone shows no grey band under it; zoomed in, it scrolls. */
.pv-scroll { overflow: auto; max-height: 72vh; background: #f1f2f2; border-radius: 6px; box-shadow: inset 0 0 0 1px #dddedf; -webkit-overflow-scrolling: touch; }
.pv-canvas { position: relative; width: 100%; }
.pv-canvas img { display: block; width: 100%; height: 100%; user-select: none; -webkit-user-select: none; }
.pv-canvas.placing { cursor: crosshair; }
.pv-canvas.placing .pv-marker { pointer-events: none; }
.pv-markers { position: absolute; inset: 0; }
.pv-marker { position: absolute; width: 26px; height: 26px; padding: 0; margin: 0; border: 0; background: none; cursor: pointer; transform: translate(-50%, -50%); filter: drop-shadow(0 0 1.5px #fff) drop-shadow(0 1px 2px rgba(0,0,0,0.45)); }
.pv-marker svg, .pv-legend svg { width: 100%; height: 100%; display: block; }
.pv-marker.focus { width: 36px; height: 36px; z-index: 2; outline: 3px solid #ff893e; outline-offset: 2px; border-radius: 50%; }
/* A measurement kept on the phone, not yet sent (js/plan_view.js drawPending). */
.pv-marker.pending { width: 20px; height: 20px; border-radius: 50%; border: 3px dashed #ff893e; background: rgba(255,137,62,0.2); cursor: default; }
.pv-marker.pending.refused { border-color: #b91c1c; background: rgba(185,28,28,0.15); }
.pv-pending { position: absolute; width: 18px; height: 18px; border-radius: 50%; border: 3px solid #ff893e; background: rgba(255,137,62,0.25); transform: translate(-50%, -50%); }
.pv-side h3 { margin: 0 0 0.25rem; font-size: 0.95rem; }
.pv-legend { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.25rem; }
.pv-legend button { display: grid; grid-template-columns: 20px 1fr auto; gap: 0.5rem; align-items: center; width: 100%; text-align: left; background: #fff; border: 1px solid #dddedf; border-radius: 4px; padding: 0.35rem 0.5rem; font: inherit; font-size: 0.82rem; cursor: pointer; }
.pv-legend button svg { width: 20px; height: 20px; }
.pv-legend button[aria-pressed="false"] { opacity: 0.4; }
.pv-legend em { font-style: normal; color: #626366; }
.pv-detail { position: relative; background: #fff; border-radius: 6px; padding: 0.75rem 1rem; box-shadow: 0 1px 4px rgba(0,0,0,0.15); margin-bottom: 1rem; font-size: 0.85rem; display: grid; gap: 0.2rem; }
.pv-detail .pv-qty { font-size: 1.15rem; font-weight: 700; color: #002b49; }
.pv-detail .pv-meta { color: #626366; }
.pv-detail p { margin: 0.25rem 0 0; }
.pv-detail img { width: 100%; max-height: 180px; object-fit: cover; border-radius: 4px; margin-top: 0.3rem; }
.pv-detail a[hidden] { display: none; }
.pv-detail-actions { display: flex; gap: 0.5rem; margin-top: 0.4rem; }
.pv-close { position: absolute; top: 0.3rem; right: 0.5rem; background: none; border: 0; font-size: 1.3rem; cursor: pointer; color: #626366; }
.pv-dialog { border: 0; border-radius: 8px; padding: 0; width: min(560px, 100vw - 1rem); max-height: 92vh; box-shadow: 0 8px 30px rgba(0,0,0,0.3); }
.pv-dialog::backdrop { background: rgba(0,43,73,0.45); }
.pv-dialog form { padding: 1.25rem; max-width: none; box-shadow: none; }
.pv-dialog h2 { margin: 0 0 0.25rem; }

@media (max-width: 768px) {
  /* Navbar */
  /* One row: brand, then user + Log out, then the menu toggle. The expanded
     menu is the only thing that wraps. Previously the user block was pushed
     onto its own full-width row and the chrome took ~250px of an 812px
     phone. */
  .navbar { flex-wrap: wrap; gap: 0.4rem; padding: 0.5rem 0.75rem; align-items: center; }
  .navbar-brand { flex: 0 0 auto; order: 0; }
  .navbar-brand span { font-size: 1.1rem !important; padding: 4px 10px !important; }
  .nav-links { display: none; order: 3; width: 100%; flex-direction: column; gap: 0; padding: 0.5rem 0; }
  .nav-links.open { display: flex; }
  .nav-links li { border-top: 1px solid rgba(255,255,255,0.1); }
  .nav-links a { display: block; padding: 0.6rem 0.25rem; font-size: 1rem; }
  .navbar-toggle { display: flex; align-items: center; background: none; border: 1px solid rgba(255,255,255,0.4); color: #fff; padding: 0.4rem 0.75rem; border-radius: 4px; cursor: pointer; font-size: 1.1rem; min-height: 44px; }
  .navbar-user { order: 1; margin-left: auto; gap: 0.4rem; }
  .navbar-user-name {
    font-size: 0.7rem; line-height: 1.1; max-width: 6.5rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .navbar-user-role { display: none; }
  .navbar form { display: flex; justify-content: flex-end; }
  .navbar-user form .btn { min-height: 36px; padding: 0.25rem 0.55rem; font-size: 0.72rem !important; }
  .navbar-toggle { order: 2; }
  /* Dropdowns on mobile: always visible inline */
  .nav-dropdown > a::after { display: none; }
  .nav-dropdown-menu { display: block; position: static; background: none; border: none; box-shadow: none; padding: 0; min-width: 0; }
  .nav-dropdown-menu a { padding-left: 1.25rem; font-size: 0.95rem; border-top: 1px solid rgba(255,255,255,0.06); }

  /* Content */
  .main-content { padding: 1rem 0.75rem; }
  .page-header { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
  .page-header .header-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; width: 100%; }
  .page-header .header-actions .btn { flex: 1; min-width: 120px; }

  /* Grids */
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .benchmark-grid, .analytics-grid { grid-template-columns: 1fr; }
  .analytics-card-wide { grid-column: span 1; }
  .detail-grid { grid-template-columns: 1fr; }
  /* A grid/flex item's default min-width:auto is its *content's* min width, so
     one wide table inside a card stretches the whole track and takes the page
     with it. The scroll wrapper can only do its job once the card is allowed
     to be narrower than what it holds. */
  .stat-card, .benchmark-card, .analytics-card, .detail-card,
  .explorer-chart-card, .table-responsive { min-width: 0; }
  .split-2, .split-3, .form-grid-2 { grid-template-columns: 1fr; }
  .ab-charts { grid-template-columns: 1fr; }
  .pv-layout { grid-template-columns: 1fr; }
  .pv-scroll { max-height: 62vh; }

  /* Tabs: one scrolling row, not four wrapped ones. A structure detail has
     nine tabs, which wrapped to ~280px of chrome and pushed the panel below
     the fold on every load. main.js scrolls the active tab into view. */
  .tab-nav {
    flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
  }
  /* margin-bottom:-2px would hang the active underline outside the scroll
     container, which now clips it. */
  .tab-btn {
    flex: 0 0 auto; white-space: nowrap; padding: 0.55rem 0.8rem;
    margin-bottom: 0;
  }

  /* Tables: horizontal scroll wrapper */
  .table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: 6px; }
  .data-table { white-space: nowrap; }
  /* Opt a prose column out of the nowrap. A sentence of criteria or notes
     held on one line makes the table wider than the scroll is worth: the
     score rubric came to 1,828px, which is not reading, it is panning. */
  .data-table .wrap-cell { white-space: normal; min-width: 12rem; }

  /* Estimate editor: reflow the spreadsheet-style table into stacked cards
     instead of horizontal scroll — every cell is a live input, so this keeps
     one DOM tree (unlike the dual-render portfolio-cards pattern above). */
  .estimate-editor, .estimate-editor thead, .estimate-editor tbody,
  .estimate-editor tr, .estimate-editor th, .estimate-editor td { display: block; white-space: normal; }
  .estimate-editor thead { display: none; }
  .estimate-editor tr.estimate-row {
    border: 1px solid #dddedf;
    border-radius: 8px;
    padding: 0.75rem;
    margin-bottom: 0.75rem;
    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    background: #fff;
  }
  .estimate-editor td { border-bottom: none; padding: 0.3rem 0; }
  .estimate-editor td::before {
    content: attr(data-label);
    display: block;
    font-size: 0.7rem;
    text-transform: uppercase;
    color: #626366;
    margin-bottom: 0.15rem;
  }
  .estimate-editor .row-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; margin-top: 0.4rem; }
  .estimate-editor .row-actions::before { content: none; }
  .estimate-editor .where-cell::before { content: none; }
  .estimate-editor .qty-input, .estimate-editor .price-input { max-width: none; }
  .row-menu-items { position: static; box-shadow: none; flex-direction: row; flex-wrap: wrap; margin-top: 0.3rem; }
  .estimate-notes-row td::before, .estimate-photos-row td::before { content: none; }
  .estimate-notes-row td, .estimate-photos-row td { padding: 0.3rem 0; }

  /* Touch targets */
  .btn { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
  .btn-sm { min-height: 36px; }
  select, input[type="text"], input[type="number"], input[type="date"],
  input[type="password"], input[type="email"], input[type="tel"],
  input[type="search"], textarea {
    min-height: 44px;
    font-size: 16px; /* prevents iOS zoom on focus */
  }
  /* Checkboxes/radios: one modest size, no padding. This used to pad the box
     to a 44px tap target with an offsetting -11px margin, which no browser
     does as intended: Safari honours the padding and draws the box at 44px,
     Chrome ignores padding on checkboxes and keeps only the negative margin,
     pulling the box over its own label. The tap target is the label instead —
     every checkbox that matters sits in one. */
  input[type="checkbox"], input[type="radio"] {
    width: 20px; height: 20px; padding: 0; margin: 0 0.4rem 0 0;
    box-sizing: border-box; flex: none; vertical-align: middle; cursor: pointer;
  }
  /* Field survey table: reflow into stacked cards, same technique as the
     estimate editor above — every cell is a live input, so this keeps one
     DOM tree. Its own class (not .estimate-editor) so the two never share
     rules that could drift apart. */
  .field-survey-table, .field-survey-table thead, .field-survey-table tbody,
  .field-survey-table tr, .field-survey-table th, .field-survey-table td { display: block; white-space: normal; }
  .field-survey-table thead { display: none; }
  /* The cards carry their own background; the table's showed as an empty
     strip under the last one. */
  .field-survey-table { background: none; box-shadow: none; border: none; }
  /* The card is the entry's tbody, not its main row: an entry is three rows
     (main, notes, photos), and with the card on the first, the notes and
     photos hung below it, outside the card (review R-147). */
  .field-survey-table tbody.field-obs-group {
    border: 1px solid #dddedf; border-radius: 8px; padding: 0.75rem;
    margin-bottom: 0.75rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); background: #fff;
  }
  .field-survey-table td { border-bottom: none; padding: 0.3rem 0; }
  .field-survey-table td::before {
    content: attr(data-label); display: block; font-size: 0.7rem;
    text-transform: uppercase; color: #626366; margin-bottom: 0.15rem;
  }
  .field-survey-table .obs-only-cell::before { content: none; }
  .field-survey-table .obs-only-label .obs-only-text { display: inline; }
  /* This checkbox sits in a real <label>, so the whole label is the tap
     target; the gap below does the spacing. */
  .field-survey-table .obs-only-label input[type="checkbox"] {
    width: 22px; height: 22px; padding: 0; margin: 0; flex: 0 0 auto;
  }
  .field-survey-table .obs-only-label {
    min-height: 44px; padding: 0.15rem 0; gap: 0.6rem; font-size: 0.85rem;
  }
  .field-survey-table .row-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; margin-top: 0.4rem; }
  .field-survey-table .row-actions::before { content: none; }
  .field-survey-table .row-actions .btn { min-height: 44px; }
  .field-obs-notes-row td::before, .field-obs-photos-row td::before { content: none; }
  .field-obs-notes-row td, .field-obs-photos-row td { padding: 0.3rem 0; }
  .field-obs-stepper-btn { width: 44px; min-height: 44px; }
  .field-survey-table select, .field-survey-table input[type=text], .field-survey-table input[type=number] {
    min-height: 44px; font-size: 16px;
  }
  /* Unit and Quantity are both short: pair them on one line instead of two
     full-width blocks. Keeps the whole entry row inside one screen. */
  .field-survey-table .unit-qty-cell {
    display: grid; grid-template-columns: 5.5rem 1fr; gap: 0 0.6rem;
    align-items: center;
  }
  .field-survey-table .unit-qty-cell .mini-label { margin: 0 0 0.15rem; }
  .field-survey-table .unit-qty-cell .mini-label:nth-of-type(1) { grid-column: 1; grid-row: 1; }
  .field-survey-table .unit-qty-cell .unit-select        { grid-column: 1; grid-row: 2; }
  .field-survey-table .unit-qty-cell .mini-label:nth-of-type(2) { grid-column: 2; grid-row: 1; }
  .field-survey-table .unit-qty-cell .field-obs-stepper  { grid-column: 2; grid-row: 2; }
  /* Tighten the label/control rhythm — it was sized for a desk form. */
  .field-survey-table .stacked-cell .mini-label { margin-top: 0.5rem; }
  .field-survey-table td { padding: 0.15rem 0; }
  .field-survey-table tbody.field-obs-group { padding: 0.6rem; margin-bottom: 0.6rem; }
  .field-obs-notes-row td, .field-obs-photos-row td { background: none; }

  /* Portfolio: hide table, show cards */
  /* The table is now inside a .table-responsive wrapper, so hide the wrapper. */
  .portfolio-cards + .table-responsive { display: none; }
  .portfolio-cards { display: block; }

  /* Charts: shorter on mobile to avoid burying content */
  .chart-container { height: 200px !important; }

  /* Forms */
  .form-card { max-width: 100%; }
  .form-actions { flex-direction: column; }
  .form-actions .btn { width: 100%; }

  /* Compare actions in structure detail */
  #compare-actions { width: 100%; }

  .condition-summary { flex-wrap: wrap; }

  /* Explore page */
  .explorer-filters .form-group { min-width: 120px; flex: 1 1 45%; }
  .explorer-match-count { margin-left: 0; flex-basis: 100%; }
  .explorer-chart-grid { grid-template-columns: 1fr; }

  /* Home page */
  .nav-search { margin: 0.5rem 0; width: 100%; }
  .home-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; }
  .home-tile { min-height: 0; padding: 0.7rem 0.8rem; font-size: 0.9rem; }
  .nav-search input { width: 100%; height: 40px; }
  .home-toolbar form { width: 100%; }
  /* Field-survey capture (body.compact-chrome): the structure and level are in
     the page heading, so search and the user name give way to the table. */
  .compact-chrome .nav-search, .compact-chrome .navbar-user-name { display: none; }
  /* Components tab: one card per component, so the planned replacement is
     on screen without scrolling the table sideways. */
  .component-life-table thead { display: none; }
  .component-life-table, .component-life-table tbody, .component-life-table tr,
  .component-life-table td { display: block; width: 100%; text-align: left !important; }
  .component-life-table tr { border: 1px solid #dddedf; border-radius: 8px; padding: 0.5rem 0.75rem;
                             margin-bottom: 0.6rem; background: #fff; }
  .component-life-table td { border: 0; padding: 0.2rem 0; white-space: normal; }
  .component-life-table td[data-label]::before {
    content: attr(data-label); display: block; font-size: 0.7rem;
    text-transform: uppercase; color: #626366;
  }
}
