/* ==========================================================================
   Corrovision brand overrides
   Loaded AFTER style.css. The vendor stylesheet is never edited -- restore
   point for it is workload-django-template/package.zip.

   Palette is taken from the logo SVGs, not chosen by eye:
     #2e8fe0  aqua blue   - the bright blue of the eye  -> primary
     #1467b8  deep blue   - the darker crescent         -> hover / dark
     #5aa9e9  light blue  - tint for gradients
     #3a414c  slate       - the pupil, the CORRO wordmark
     #d3d7dc  light grey  - the pale half of the eye

   Green is NOT removed from the product -- it stops being the brand colour
   and stays semantic (positive / passing readings, which for cathodic
   protection is the reading that meets the -850 mV criterion).
   ========================================================================== */

:root {
  --primary: #2e8fe0;
  --primary-light: #5aa9e9;
  --primary-hover: #1467b8;
  --primary-dark: #1467b8;

  --rgba-primary-1: rgba(46, 143, 224, 0.1);
  --rgba-primary-2: rgba(46, 143, 224, 0.2);
  --rgba-primary-3: rgba(46, 143, 224, 0.3);
  --rgba-primary-4: rgba(46, 143, 224, 0.4);
  --rgba-primary-5: rgba(46, 143, 224, 0.5);
  --rgba-primary-6: rgba(46, 143, 224, 0.6);
  --rgba-primary-7: rgba(46, 143, 224, 0.7);
  --rgba-primary-8: rgba(46, 143, 224, 0.8);
  --rgba-primary-9: rgba(46, 143, 224, 0.9);

  /* Brand tokens for our own components later on. */
  --cv-slate: #3a414c;
  --cv-slate-dark: #23272f;
  --cv-grey: #b9c0c7;
  --cv-grey-light: #d3d7dc;
}

/* ==========================================================================
   Brand lockup — stacked

   Two marks live in the markup and exactly one is ever visible:

     .logo-stacked  eye above wordmark (100x61.28 native) -- EXPANDED sidebar
     .logo-abbr     square eye only    (60x60 native)     -- COLLAPSED sidebar

   The swap is not cosmetic. The stacked asset carries its own wordmark, and a
   collapsed sidebar is ~80px wide; leaving the stacked version in place there
   renders the wordmark at roughly 8px, i.e. unreadable. So every state in
   which the vendor hides .brand-title must also hide .logo-stacked and bring
   .logo-abbr back. Those states are enumerated below and mirror style.css
   exactly -- full+menu-toggle, compact, mini, modern, icon-hover, and the
   <768px media query.

   The HTML .brand-title (CORROVISION / CATHODIC PROTECTION) is retired: that
   text is inside the stacked SVG now, and keeping both would double it.
   ========================================================================== */

.nav-header .brand-logo {
  align-items: center;
  justify-content: center;   /* stacked marks read centred, not left-aligned */
  padding-left: 0;
  padding-right: 0;
}

/* --- default / expanded: stacked visible, square mark hidden -------------- */

.nav-header .logo-stacked {
  display: block;
  width: 9.375rem;           /* 150px -> 92px tall in a 120px header */
  height: auto;
  max-width: 78%;            /* never crowd the 328px header */
}

.nav-header .logo-abbr {
  display: none;
}

/* Text is in the SVG now. */
.nav-header .brand-title {
  display: none;
}

@media only screen and (max-width: 87.5rem) {
  .nav-header .logo-stacked {
    width: 8.5rem;           /* 136px */
  }
}

/* --- collapsed: square mark visible, stacked hidden ----------------------- */
/* Mirrors every selector style.css uses to hide .brand-title. */

[data-sidebar-style="full"][data-layout="vertical"] .menu-toggle .nav-header .logo-stacked,
[data-sidebar-style="compact"][data-layout="vertical"] .nav-header .logo-stacked,
[data-sidebar-style="mini"] .nav-header .logo-stacked,
[data-sidebar-style="modern"][data-layout="vertical"] .nav-header .logo-stacked,
[data-sidebar-style="icon-hover"][data-layout="vertical"] .nav-header .logo-stacked {
  display: none;
}

[data-sidebar-style="full"][data-layout="vertical"] .menu-toggle .nav-header .logo-abbr,
[data-sidebar-style="compact"][data-layout="vertical"] .nav-header .logo-abbr,
[data-sidebar-style="mini"] .nav-header .logo-abbr,
[data-sidebar-style="modern"][data-layout="vertical"] .nav-header .logo-abbr,
[data-sidebar-style="icon-hover"][data-layout="vertical"] .nav-header .logo-abbr {
  display: block;
  width: 3.25rem;
  height: 3.25rem;
  max-width: 3.25rem;
}

@media only screen and (max-width: 47.9375rem) {
  .nav-header .logo-stacked {
    display: none;
  }
  .nav-header .logo-abbr {
    display: block;
    width: 2.75rem;
    height: 2.75rem;
    max-width: 2.75rem;
  }
}

/* ==========================================================================
   Auth screens — login / register / lock-screen / forgot-password

   These use the stacked lockup too. Larger than the sidebar copy because it is
   the hero of an otherwise empty card and has the width to carry it.
   Its wrapper is already .text-center, so no extra centring is needed --
   the img just needs to stop being inline so the margin auto applies cleanly
   at narrow widths.

   NOTE: /ecom-invoice/ deliberately keeps the HORIZONTAL lockup. It sits in a
   letterhead row beside the invoice meta, where a stacked mark would push the
   header height out and misalign the columns.
   ========================================================================== */

/* ==========================================================================
   Route schematic + Area/Zone tree

   A world map was the wrong picture: a CP zone is an electrical circuit, not a
   territory. What matters is WHERE along the pipe an asset sits, so assets are
   pinned by chainage on a linear route under the potential profile — the pin
   and the dip in the chart line up on the same x-axis.
   ========================================================================== */

.cv-tree { list-style: none; padding: 0; margin: 0; }

.cv-area {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  font-size: 0.8125rem;
  color: var(--cv-slate-dark);
  padding: 0.625rem 0 0.375rem;
  border-top: 1px solid #f2f4f6;
}

.cv-tree > .cv-area:first-child { border-top: 0; }

.cv-area-code {
  background: var(--rgba-primary-1);
  color: var(--primary);
  border-radius: 0.375rem;
  padding: 0.0625rem 0.375rem;
  font-size: 0.6875rem;
}

.cv-area-n { margin-left: auto; font-weight: 400; font-size: 0.6875rem; color: #98a2ad; }

.cv-zone-list { list-style: none; padding: 0 0 0 0.5rem; margin: 0 0 0.25rem; }

.cv-zone {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3125rem 0.5rem;
  border-radius: 0.5rem;
  font-size: 0.8125rem;
  color: #5b656f;
  cursor: default;
}

.cv-zone:hover { background: #f6f8fa; }
.cv-zone-id { font-size: 0.6875rem; color: #98a2ad; min-width: 2.25rem; }
.cv-zone-name { flex: 1 1 auto; }
.cv-zone .cv-dot { margin-right: 0; }

/* ---- the chainage route ---- */
.cv-route { position: relative; height: 3.25rem; margin: 0.5rem 0 0; }

.cv-route-line {
  position: absolute;
  left: 0; right: 0; top: 1rem;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(to right,
    #2BB673 0%, #2BB673 58%, #E15554 62%, #E15554 82%, #2BB673 86%, #2BB673 100%);
}

.cv-pin {
  position: absolute;
  top: 0.5rem;
  width: 0.75rem; height: 0.75rem;
  border-radius: 50%;
  border: 2px solid #fff;
  transform: translateX(-50%);
  box-shadow: 0 0 0 1px rgba(35, 39, 47, 0.12);
}

.cv-pin-tp   { background: var(--primary); }
.cv-pin-rect { background: var(--cv-slate-dark); border-radius: 2px; width: 0.8125rem; height: 0.8125rem; }
.cv-pin-gb   { background: #8FC5EE; }
.cv-pin-def  { background: #E15554; }
.cv-pin-ac   { background: #E0A32E; }

.cv-pin-label {
  position: absolute;
  top: 1.25rem; left: 50%;
  transform: translateX(-50%);
  font-size: 0.625rem;
  color: #98a2ad;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.15s ease;
  pointer-events: none;
}

.cv-pin:hover { z-index: 3; }
.cv-pin:hover .cv-pin-label { opacity: 1; }

.cv-route-scale {
  display: flex;
  justify-content: space-between;
  font-size: 0.6875rem;
  color: #98a2ad;
  border-top: 1px solid #f2f4f6;
  padding-top: 0.5rem;
}

.cv-pin-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 0.75rem;
  font-size: 0.6875rem;
  color: #75808c;
}

.cv-pin-key { display: inline-flex; align-items: center; gap: 0.375rem; }
.cv-pin-key .cv-pin { position: static; transform: none; top: auto; }

/* ==========================================================================
   Corrective-action board (replaces the theme's generic Kanban)
   ========================================================================== */

.cv-kb-col { margin-bottom: 1.5rem; }

.cv-kb-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.25rem;
}

.cv-kb-count {
  font-size: 0.8125rem;
  font-weight: 600;
  color: #98a2ad;
}

/* The theme sets `.card { height: calc(100% - 30px) }` globally, so the FIRST
   card in a stacked column swelled to the full column height and shoved the
   rest below the fold. Same root cause as the module-card overlap. Cards that
   stack must size to their content. */
.cv-kb-card {
  height: auto;
  margin-bottom: 0.875rem;
  border: 1px solid #eef0f3;
  box-shadow: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.cv-kb-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 0.5rem 1.25rem rgba(35, 39, 47, 0.08);
}

.cv-kb-card .card-body { padding: 1rem; }
.cv-kb-card h6 { color: var(--cv-slate-dark); }

.cv-kb-foot {
  display: flex;
  justify-content: space-between;
  border-top: 1px solid #f2f4f6;
  padding-top: 0.625rem;
}

@media (prefers-reduced-motion: reduce) {
  .cv-kb-card { transition: none; }
  .cv-kb-card:hover { transform: none; }
}

/* ==========================================================================
   Table consistency — ONE rule for every table in the product

   Headers bold, cell data never bold, status always a badge. The theme shipped
   tables where random cells were <strong> and status was sometimes a coloured
   word, sometimes a pill, sometimes nothing. Inconsistent emphasis is worse
   than no emphasis: if half the cells are bold, bold stops meaning anything.
   The ONE exception is a reading that carries the verdict (a potential in mV),
   which keeps .cv-num-strong.
   ========================================================================== */

.table > thead > tr > th,
table.dataTable > thead > tr > th {
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cv-slate);
  white-space: nowrap;
}

.table > tbody > tr > td,
table.dataTable > tbody > tr > td {
  font-weight: 400;
  color: #4b5560;
  vertical-align: middle;
}

/* the one deliberate exception: identifiers and measured values */
.table td .cv-id,
.table td .cv-num-strong {
  font-weight: 600;
  color: var(--cv-slate-dark);
}

.table td .cv-num-strong { font-variant-numeric: tabular-nums; }

/* ---- status badges: one vocabulary, used everywhere ---- */
.cv-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  border-radius: 999px;
  padding: 0.25rem 0.625rem;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
}

.cv-badge::before {
  content: '';
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

.cv-badge-green { background: rgba(43, 182, 115, 0.12);  color: #1e8b57; }
.cv-badge-amber { background: rgba(224, 163, 46, 0.14);  color: #a8761a; }
.cv-badge-red   { background: rgba(225, 85, 84, 0.12);   color: #c0403f; }
.cv-badge-blue  { background: var(--rgba-primary-1);     color: var(--primary); }
.cv-badge-grey  { background: #f0f2f5;                   color: #75808c; }

/* ==========================================================================
   KPI table — RAG scale instead of three raw band columns

   The reference screen prints Green/Amber/Red bands as three text columns
   ("70 - 100", "55 - 69", "0 - 54") and leaves the reader to work out where the
   actual falls. One bar with the target marked on it answers that instantly,
   and the written verdict means colour is never the only signal.
   ========================================================================== */

.cv-kpi th {
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #98a2ad;
  font-weight: 600;
}

.cv-kpi td { vertical-align: middle; }

.cv-rag-bar {
  position: relative;
  display: block;
  height: 6px;
  border-radius: 999px;
  background: #eef0f3;
  overflow: visible;
}

.cv-rag-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  border-radius: 999px;
}

/* the target marker — a notch, so "where should we be" is always visible */
.cv-rag-target {
  position: absolute;
  top: -3px;
  width: 2px;
  height: 12px;
  background: var(--cv-slate-dark);
  border-radius: 1px;
}

/* ==========================================================================
   Inspection-cycle timeline
   ========================================================================== */

.cv-timeline { list-style: none; padding: 0; margin: 0; position: relative; }

.cv-timeline::before {
  content: '';
  position: absolute;
  left: 0.4375rem; top: 0.5rem; bottom: 0.5rem;
  width: 2px;
  background: #eef0f3;
}

.cv-timeline > li {
  position: relative;
  padding-left: 2rem;
  padding-bottom: 1.5rem;
}

.cv-timeline > li:last-child { padding-bottom: 0; }

.cv-timeline .timeline-badge {
  position: absolute;
  left: 0; top: 0.3125rem;
  width: 1rem; height: 1rem;
  border-radius: 50%;
  border: 3px solid #fff;
  box-shadow: 0 0 0 2px currentColor;
}

.cv-tl-green { color: #2BB673; background: #2BB673; }
.cv-tl-amber { color: #E0A32E; background: #E0A32E; }
.cv-tl-red   { color: #E15554; background: #E15554; }
.cv-tl-blue  { color: var(--primary); background: var(--primary); }
.cv-tl-grey  { color: #C4CBD3; background: #fff; }

.cv-tl-when {
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #98a2ad;
  display: block;
  margin-bottom: 0.125rem;
}

.cv-tl-panel h6 { color: var(--cv-slate-dark); font-size: 0.9375rem; }

/* ==========================================================================
   Survey form — grouped fieldsets + live verdict
   ========================================================================== */

.cv-fieldset {
  border: 0;
  padding: 0;
  margin-bottom: 1.5rem;
}

.cv-fieldset > legend {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #98a2ad;
  border-bottom: 1px solid #eef0f3;
  padding-bottom: 0.5rem;
  margin-bottom: 1rem;
  width: 100%;
  float: none;
}

/* Invalid state is applied on SUBMIT only -- see cp-survey-form.js. */
.cv-fieldset .is-invalid {
  border-color: #E15554;
}

.cv-verdict {
  display: flex;
  align-items: center;
  border-radius: 0.75rem;
  padding: 0.875rem 1rem;
  font-weight: 600;
  font-size: 0.9375rem;
}

.cv-verdict-idle { background: #f4f6f8; color: #98a2ad; }
.cv-verdict-pass { background: rgba(43, 182, 115, 0.12); color: #1e8b57; }
.cv-verdict-fail { background: rgba(225, 85, 84, 0.12); color: #c0403f; }

.cv-verdict-card { position: sticky; top: 1rem; }

/* ==========================================================================
   Module tiles — the launcher strip on the dashboard

   Compact deliberately: icon, name, one live figure. The full card with its
   description lives on /clients/. Putting eight full cards at the top of the
   dashboard would have re-created the clutter we just removed; this gives the
   same "pick a module, land in its detail" navigation in one row.
   ========================================================================== */

.cv-tiles { margin-bottom: 0.5rem; }

.cv-tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  background: #fff;
  border-radius: 1rem;
  padding: 1.125rem 1rem;
  height: 100%;
  margin-bottom: 1.5rem;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.cv-tile:hover {
  transform: translateY(-4px);
  box-shadow: 0 0.75rem 1.5rem rgba(35, 39, 47, 0.1);
}

.cv-tile-icon {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--rgba-primary-1);
  color: var(--primary);
  margin-bottom: 0.75rem;
}

.cv-tile:hover .cv-tile-icon { background: var(--primary); color: #fff; }
.cv-tile-icon svg { width: 1.375rem; height: 1.375rem; }

.cv-tile-name {
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--cv-slate-dark);
  line-height: 1.2;
}

.cv-tile-figure {
  font-size: 0.75rem;
  color: #98a2ad;
  margin-top: 0.1875rem;
}

@media (prefers-reduced-motion: reduce) {
  .cv-tile { transition: none; }
  .cv-tile:hover { transform: none; }
}

/* ==========================================================================
   Floating chat assistant — bottom-right

   Was a full-width ask box pinned above the dashboard. That put a permanent
   band of chrome between the user and their data on every single page, which
   is exactly the clutter we were trying to remove. A launcher bubble costs
   56px in a corner and the panel only exists when asked for.
   ========================================================================== */

.cv-chat-fab {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  border: 0;
  background: var(--primary);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0.5rem 1.5rem rgba(46, 143, 224, 0.4);
  z-index: 1040;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.cv-chat-fab:hover {
  transform: translateY(-2px) scale(1.04);
  box-shadow: 0 0.75rem 1.75rem rgba(46, 143, 224, 0.5);
}

.cv-chat-fab:focus-visible { outline: 3px solid #1467b8; outline-offset: 3px; }
.cv-chat-fab svg { width: 1.5rem; height: 1.5rem; }
.cv-chat-fab .cv-chat-close-icon { display: none; }
.cv-chat-open .cv-chat-fab .cv-chat-open-icon { display: none; }
.cv-chat-open .cv-chat-fab .cv-chat-close-icon { display: block; }

/* unread ping on the bubble */
.cv-chat-fab::after {
  content: '';
  position: absolute;
  top: 0.25rem; right: 0.25rem;
  width: 0.625rem; height: 0.625rem;
  border-radius: 50%;
  background: #E15554;
  border: 2px solid #fff;
}
.cv-chat-open .cv-chat-fab::after { display: none; }

.cv-chat-panel {
  position: fixed;
  right: 1.5rem;
  bottom: 5.5rem;
  width: 23rem;
  max-width: calc(100vw - 3rem);
  max-height: min(32rem, calc(100vh - 8rem));
  background: #fff;
  border-radius: 1.125rem;
  box-shadow: 0 1.5rem 3rem rgba(35, 39, 47, 0.18);
  z-index: 1039;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.75rem) scale(0.98);
  transform-origin: bottom right;
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}

.cv-chat-open .cv-chat-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.cv-chat-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.125rem;
  border-bottom: 1px solid #eef0f3;
  flex: 0 0 auto;
}

.cv-chat-head img { width: 2rem; height: 2rem; }
.cv-chat-head h6 { margin: 0; font-size: 0.9375rem; color: var(--cv-slate-dark); }
.cv-chat-head small { color: #98a2ad; font-size: 0.75rem; }

.cv-chat-body {
  padding: 1.125rem;
  overflow-y: auto;
  flex: 1 1 auto;
}

.cv-msg {
  background: #f4f6f8;
  border-radius: 0.875rem 0.875rem 0.875rem 0.25rem;
  padding: 0.75rem 0.875rem;
  font-size: 0.8438rem;
  line-height: 1.5;
  color: var(--cv-slate-dark);
  margin-bottom: 0.75rem;
}

.cv-msg-me {
  background: var(--primary);
  color: #fff;
  border-radius: 0.875rem 0.875rem 0.25rem 0.875rem;
  margin-left: auto;
  max-width: 85%;
}

.cv-chat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-top: 0.25rem;
}

.cv-chip {
  background: var(--rgba-primary-1);
  border: 0;
  border-radius: 999px;
  padding: 0.375rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--primary);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
  display: inline-flex;
  align-items: center;
}

.cv-chip:hover { background: var(--primary); color: #fff; }
.cv-chip:hover .cv-dot { filter: brightness(1.9); }

.cv-chat-foot {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 0.875rem;
  border-top: 1px solid #eef0f3;
  flex: 0 0 auto;
}

.cv-chat-foot input {
  flex: 1 1 auto;
  border: 0;
  outline: 0;
  background: transparent;
  font-size: 0.875rem;
  color: var(--cv-slate-dark);
  min-width: 0;
}

.cv-chat-send {
  width: 2.125rem;
  height: 2.125rem;
  border-radius: 50%;
  border: 0;
  background: var(--primary);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

@media (prefers-reduced-motion: reduce) {
  .cv-chat-fab, .cv-chat-panel, .cv-chip { transition: none; }
  .cv-chat-fab:hover { transform: none; }
}

/* ==========================================================================
   Section dividers

   The dashboard was one continuous wall of cards, which is what read as
   "cluttered". Named bands give the page the shape of the client's own loop:
   Protection Status -> Plan vs Actual -> Evidence -> Corrective Actions.
   The rule is hairline and the label is small-caps slate, so the divider
   organises without competing with the cards it separates.
   ========================================================================== */

.cv-section {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 0.5rem 0 1.25rem;
}

.cv-section:not(:first-child) {
  margin-top: 1.75rem;
}

.cv-section-title {
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--cv-slate);
  margin: 0;
  white-space: nowrap;
}

.cv-section-title .cv-section-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 50%;
  background: var(--rgba-primary-1);
  color: var(--primary);
  font-size: 0.6875rem;
  margin-right: 0.5rem;
}

.cv-section-rule {
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(to right, #e4e7eb, rgba(228, 231, 235, 0));
}

.cv-section-note {
  font-size: 0.75rem;
  color: #98a2ad;
  white-space: nowrap;
}

/* ==========================================================================
   Module launcher cards  (built on the theme's .contact-bx grid)
   ========================================================================== */

/* The gap between rows was ZERO — measured, not guessed: row 1 bottom 440px,
   row 2 top 440px. Cause: `height: 100%` sized the card to the FULL column,
   so the theme's 26.25px card margin had nowhere to go and the next row began
   flush against the previous one. Reading as "overlapping boxes" was fair.
   Fix: the gap belongs to the COLUMN (padding-bottom), the card fills what's
   left. Card margin zeroed so the two can't fight. */
.cv-module-col {
  padding-bottom: 1.875rem;
  display: flex;
}

.cv-module {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  margin-bottom: 0;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.cv-module .card-body {
  padding: 1.625rem;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

/* Pushes the figures row to the card bottom so all cards align on it,
   whatever the description length. */
.cv-module .cv-module-meta {
  margin-top: auto;
}

.cv-module:hover {
  transform: translateY(-4px);
  box-shadow: 0 0.75rem 1.75rem rgba(35, 39, 47, 0.11);
}

.cv-module .cv-module-icon {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 0.875rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--rgba-primary-1);
  color: var(--primary);
  flex: 0 0 auto;
}

.cv-module:hover .cv-module-icon {
  background: var(--primary);
  color: #fff;
}

.cv-module .cv-module-icon svg {
  width: 1.75rem;
  height: 1.75rem;
}

.cv-module h4 {
  color: var(--cv-slate-dark);
  margin-bottom: 0.125rem;
}

.cv-module .cv-module-sub {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--primary);
}

.cv-module .cv-module-desc {
  font-size: 0.8125rem;
  color: #7e8892;
  line-height: 1.5;
  min-height: 3.9em;
}

.cv-module .cv-module-meta {
  border-top: 1px solid #eef0f3;
  padding-top: 0.75rem;
  font-size: 0.8125rem;
}

@media (prefers-reduced-motion: reduce) {
  .cv-module { transition: none; }
  .cv-module:hover { transform: none; }
}

/* ==========================================================================
   Status language — DOTS, not filled blocks

   The first cut filled whole cards amber and red, which turned a blue/grey/green
   theme into a yellow-and-red alarm panel. Correct for a control room, wrong for
   this product. The traffic-light SEMANTICS stay (the client asked for them
   explicitly) but the VOLUME drops: colour now appears as a 8px dot and a 4px
   bar. Blue, grey and green carry the page; red and amber are found when looked
   for, not shouted.

   Tones are deliberately muted versions of pure signal colours -- #E15554 not
   #FF0000 -- so they sit with the brand blue rather than vibrating against it.
   ========================================================================== */

.cv-dot {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  margin-right: 0.5rem;
  vertical-align: middle;
  flex: 0 0 auto;
}

.cv-dot-green { background: #2BB673; }
.cv-dot-amber { background: #E0A32E; }
.cv-dot-red   { background: #E15554; }
.cv-dot-blue  { background: var(--primary); }
.cv-dot-grey  { background: #B9C0C7; }

.cv-bar-green { background: #2BB673; }
.cv-bar-amber { background: #E0A32E; }
.cv-bar-red   { background: #E15554; }
.cv-bar-grey  { background: #B9C0C7; }

/* Big numbers read as data, not as alarms: slate, never coloured. */
.cv-stat .cv-num,
.cv-horizon .cv-num {
  color: var(--cv-slate-dark);
  letter-spacing: -0.02em;
}

/* Keeps the four numbers on one baseline when a label wraps to two lines. */
.cv-stat-label {
  min-height: 2.6em;
  line-height: 1.3;
}

.cv-horizon {
  display: flex;
  align-items: flex-start;
  border: 1px solid #eef0f3;
  border-radius: 0.75rem;
  padding: 1rem 1.25rem;
  height: 100%;
}

.cv-horizon .cv-dot {
  margin-top: 0.6rem;
}

/* --- motion: subtle, and only on hover / entry --- */
.cv-stat,
.cv-horizon {
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.cv-stat:hover,
.cv-horizon:hover {
  transform: translateY(-3px);
  box-shadow: 0 0.5rem 1.5rem rgba(35, 39, 47, 0.09);
}

@media (prefers-reduced-motion: reduce) {
  .cv-stat, .cv-horizon { transition: none; }
  .cv-stat:hover, .cv-horizon:hover { transform: none; }
}

/* ==========================================================================
   CP dashboard stat cards

   "Partially Protected" is the only label of the four that wraps to two lines,
   which dropped its number ~20px below the other three and broke the baseline
   across the row. Reserving two lines on every label keeps the numbers aligned
   regardless of label length, rather than shortening the term -- "Partially
   Protected" is the client's own wording and a CP engineer's term of art.
   ========================================================================== */

.widget-stat .media-body > p {
  min-height: 2.6em;
  margin-bottom: 0.25rem;
  line-height: 1.3;
}

.widget-stat .media-body > small {
  display: block;
  min-height: 2.6em;
  line-height: 1.3;
}

.auth-logo {
  display: block;
  width: 11.25rem;        /* 180px -> ~110px tall */
  max-width: 60%;
  height: auto;
  /* The wrapper's .mb-3 alone left the wordmark sitting on top of the
     "Sign in your account" heading. The stacked mark has almost no optical
     padding under the type, so it needs the separation the horizontal
     lockup did not. */
  margin: 0 auto 0.5rem;
}

/* ==========================================================================
   Inspection calendar — month grid built for field work, not appointments
   ========================================================================== */

.cv-cal { table-layout: fixed; }
.cv-cal > thead > tr > th { text-align: center; padding: 0.5rem; }

.cv-cal-cell {
  height: 7.5rem;
  vertical-align: top !important;
  border: 1px solid #f2f4f6;
  padding: 0.5rem !important;
}

.cv-cal-empty { background: #fafbfc; }
.cv-cal-busy  { background: #fcfdff; }

.cv-cal-day {
  display: block;
  font-size: 0.6875rem;
  font-weight: 600;
  color: #98a2ad;
  margin-bottom: 0.25rem;
}

.cv-cal-ev {
  display: block;
  font-size: 0.625rem;
  line-height: 1.3;
  border-radius: 0.25rem;
  padding: 0.1875rem 0.3125rem;
  margin-bottom: 0.1875rem;
  border-left: 2px solid currentColor;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cv-cal-green { background: rgba(43,182,115,.10);  color: #1e8b57; }
.cv-cal-amber { background: rgba(224,163,46,.12);  color: #a8761a; }
.cv-cal-red   { background: rgba(225,85,84,.10);   color: #c0403f; }
.cv-cal-blue  { background: var(--rgba-primary-1); color: var(--primary); }
.cv-cal-grey  { background: #f0f2f5;               color: #75808c; }

/* ==========================================================================
   Accordion — readability fix

   The theme's .accordion-primary paints the whole button solid brand blue and
   leaves the label dark slate on top of it: black-on-blue, which failed
   contrast badly enough to be genuinely hard to read. Rebuilt as a light
   surface with slate text; the OPEN item gets a blue left rule and tinted
   background so state is still obvious without a full-bleed blue block.
   ========================================================================== */

.accordion-primary .accordion-item,
#stdAcc .accordion-item {
  background: transparent;
  border: 1px solid #eef0f3;
  border-radius: 0.875rem !important;
  margin-bottom: 0.75rem;
  overflow: hidden;
  box-shadow: none;
}

.accordion-primary .accordion-button,
#stdAcc .accordion-button {
  background: #fff !important;
  color: var(--cv-slate-dark) !important;
  box-shadow: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  padding: 1rem 1.25rem;
  font-weight: 500;
  font-size: 0.9375rem;
}

.accordion-primary .accordion-button:not(.collapsed),
#stdAcc .accordion-button:not(.collapsed) {
  background: var(--rgba-primary-1) !important;
  color: var(--primary) !important;
  box-shadow: inset 3px 0 0 var(--primary) !important;
}

.accordion-primary .accordion-button:focus,
#stdAcc .accordion-button:focus { outline: 0; box-shadow: none; }

.accordion-primary .accordion-button::after,
#stdAcc .accordion-button::after { filter: none; opacity: 0.55; }

.accordion-primary .accordion-body,
#stdAcc .accordion-body {
  background: #fff;
  padding: 0 1.25rem 1.25rem;
  color: #5b656f;
  font-size: 0.875rem;
  line-height: 1.6;
}

/* the standard code chip inside the button */
#stdAcc .accordion-button .cv-id {
  background: #f0f2f5;
  color: var(--cv-slate-dark);
  border-radius: 0.375rem;
  padding: 0.125rem 0.5rem;
  font-size: 0.75rem;
  white-space: nowrap;
}

#stdAcc .accordion-button:not(.collapsed) .cv-id {
  background: var(--primary);
  color: #fff;
}

/* ==========================================================================
   Weekly inspection calendar

   The month grid forced ~10px type and truncated every event to
   "Rectifier check — SGP…", which tells a planner nothing. A week gives each
   day a full column: readable type, plus the crew and the driving clause.
   ========================================================================== */

.cv-week { --cv-wk-gap: 0.5rem; }

.cv-wk-col {
  min-width: 0;
  border-radius: 0.75rem;
  padding: 0.75rem 0.625rem;
  background: #fafbfc;
}

.cv-wk-today { background: var(--rgba-primary-1); }

.cv-wk-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-bottom: 0.5rem;
  margin-bottom: 0.625rem;
  border-bottom: 1px solid #e9edf1;
}

.cv-wk-dow {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #98a2ad;
}

.cv-wk-num { font-size: 1.125rem; font-weight: 600; color: var(--cv-slate-dark); }
.cv-wk-today .cv-wk-num { color: var(--primary); }

.cv-wk-ev {
  background: #fff;
  border-radius: 0.625rem;
  border-left: 3px solid currentColor;
  padding: 0.625rem 0.75rem;
  margin-bottom: 0.5rem;
}

.cv-wk-green { color: #1e8b57; }
.cv-wk-amber { color: #a8761a; }
.cv-wk-red   { color: #c0403f; }
.cv-wk-blue  { color: var(--primary); }
.cv-wk-grey  { color: #75808c; }

.cv-wk-time  { font-size: 0.6875rem; font-weight: 600; }

.cv-wk-title {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--cv-slate-dark);
  margin: 0.125rem 0 0.1875rem;
  line-height: 1.3;
}

.cv-wk-det { font-size: 0.75rem; color: #7e8892; margin: 0 0 0.5rem; line-height: 1.4; }

.cv-wk-meta {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  font-size: 0.6875rem;
  color: #98a2ad;
  border-top: 1px solid #f2f4f6;
  padding-top: 0.375rem;
}

.cv-wk-empty {
  font-size: 0.75rem;
  color: #b3bcc6;
  text-align: center;
  padding: 1.5rem 0;
}

/* The theme paints .accordion-header solid var(--primary) and puts dark text on
   it -- black on blue, which is what made this unreadable. Overriding item and
   button was not enough because the colour lives on the HEADER. Cleanest fix is
   to stop using .accordion-primary at all: .cv-accordion owns its own styling
   and never inherits the theme's colour block. */
.cv-accordion .accordion-header {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  margin: 0;
}

.cv-accordion .accordion-item {
  background: #fff;
  border: 1px solid #eef0f3;
  border-radius: 0.875rem !important;
  margin-bottom: 0.75rem;
  overflow: hidden;
  box-shadow: none;
}

.cv-accordion .accordion-button {
  background: #fff !important;
  color: var(--cv-slate-dark) !important;
  box-shadow: none !important;
  border: 0 !important;
  padding: 1rem 1.25rem;
  font-weight: 500;
  font-size: 0.9375rem;
}

.cv-accordion .accordion-button:not(.collapsed) {
  background: var(--rgba-primary-1) !important;
  color: var(--primary) !important;
  box-shadow: inset 3px 0 0 var(--primary) !important;
}

.cv-accordion .accordion-button:focus { outline: 0; box-shadow: none; }
.cv-accordion .accordion-button::after { filter: none; opacity: 0.5; }

.cv-accordion .accordion-body {
  background: #fff;
  padding: 0 1.25rem 1.25rem;
  color: #5b656f;
  font-size: 0.875rem;
  line-height: 1.6;
}

.cv-accordion .accordion-button .cv-id {
  background: #f0f2f5;
  color: var(--cv-slate-dark);
  border-radius: 0.375rem;
  padding: 0.125rem 0.5rem;
  font-size: 0.75rem;
  white-space: nowrap;
}

.cv-accordion .accordion-button:not(.collapsed) .cv-id {
  background: var(--primary);
  color: #fff;
}

/* Sign-in error — inserted by cp-auth.js, so it needs a style even though it
   never appears in the markup. */
.cv-signin-error {
  background: rgba(225, 85, 84, 0.12);
  color: #c0403f;
  border-radius: 0.625rem;
  padding: 0.625rem 0.875rem;
  font-size: 0.8125rem;
  font-weight: 600;
  margin-bottom: 1rem;
}
