/**
 * InstallaCRM Custom Styles (fixes.css)
 * ======================================
 * Custom CSS classes and overrides for the InstallaCRM application.
 * This file supplements the Bootstrap/Falcon theme with app-specific styles. Every colour, size, radius and shadow
 * comes from public/assets/css/tokens.css (ticket 0107); write var(--token), never a new hex value.
 *
 * Table of Contents:
 * 0. Layout Stability (CLS Prevention)
 * 1. Navigation Styles
 * 2. Typography (Font Sizes)
 * 3. Page Background (the canvas) and the frame (sidebar, top bar)
 * 4. Form Helpers
 * 5. Utility Classes
 * 6. Card surfaces (one solid card; glass, clear and solid are aliases)
 * 7. Text on surfaces and on the canvas
 * 8. Button roles and state chips
 * 9. Form Input Adjustments
 * 10. Card Header/Body/Footer Contrast
 * 11. Table Styles
 * 12. Development Helpers
 * 13. User Badge Component
 * 14. Content Editable Styles
 * 15. Noteboard Component
 * 16. Address/Map Styles
 * 17. Form Help Blocks
 * 18. Scrollbar Styles
 * 19. Cursor Utilities
 * 20. Design System Primitives (components/general)
 * 21. Card header defaults
 */


/* ==========================================================================
   0. LAYOUT STABILITY (CLS Prevention)
   ========================================================================== */

/**
 * Alpine.js x-cloak - hide elements until Alpine initializes
 * Prevents flash of unstyled/unhidden content
 */
[x-cloak] {
  display: none !important;
}

/**
 * Aspect ratio utilities for preventing layout shift on images
 * Usage: <div class="aspect-ratio-16x9"><img src="..." /></div>
 */
.aspect-ratio-1x1 { aspect-ratio: 1 / 1; }
.aspect-ratio-4x3 { aspect-ratio: 4 / 3; }
.aspect-ratio-16x9 { aspect-ratio: 16 / 9; }
.aspect-ratio-21x9 { aspect-ratio: 21 / 9; }

/**
 * Image containers - ensure images don't cause layout shift
 * Images inside these containers will fill and maintain aspect ratio
 */
.img-container {
  position: relative;
  overflow: hidden;
}

.img-container img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/**
 * Avatar sizing - explicit dimensions to prevent reflow
 * Used in navigation and user displays
 */
.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-xl {
  width: 40px;
  height: 40px;
}

.avatar-l {
  width: 36px;
  height: 36px;
}

.avatar-m {
  width: 32px;
  height: 32px;
}

.avatar-s {
  width: 24px;
  height: 24px;
}

/**
 * Reserve space for sidebar to prevent content shift
 * The sidebar width is known, so we reserve space immediately
 */
.navbar-vertical.navbar-expand-xl {
  min-width: 250px;
}

.navbar-vertical.navbar-expand-xl.navbar-vertical-collapsed {
  min-width: 56px;
}

/**
 * Skeleton loader placeholder - use for async content
 * Prevents layout shift by reserving space
 */
.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeleton-loading 1.5s infinite;
  border-radius: 4px;
}

@keyframes skeleton-loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/**
 * Content stability - prevent font-loading shifts
 * Apply to text areas that might shift when fonts load
 */
.content-stable {
  font-synthesis: none;
  text-rendering: optimizeLegibility;
}

/**
 * Card and photo thumbnail consistent heights
 */
.thumb-square {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.thumb-landscape {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.thumb-wide {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}


/* ==========================================================================
   1. NAVIGATION STYLES
   ========================================================================== */

/**
 * The frame: the sidebar and the top bar (tokens.css --frame-*, --top-bar). On a desk the sidebar is see-through on
 * the canvas and the top bar paints the canvas itself (fixed to the window, as the body's is), so it is the same blue
 * whether the page is scrolled or not. Scrolled, the theme's navbar-top.js adds .navbar-glass-shadow; that adds a
 * hairline under the bar and nothing else: no colour of its own, no blur. Under 1200px wide both are solid.
 * The admin panel and the designer and map screens (data-look="legacy") keep the rules from before ticket 0107, below.
 */
[data-look="app"] .navbar-vertical .navbar-vertical-content {
  color: var(--on-frame);
}

[data-look="app"] .navbar-top {
  color: var(--on-top-bar);
}

/* The theme colours the sidebar's links through its own variables (at a higher specificity than a rule here) */
[data-look="app"] .navbar-vertical {
  --installa-navbar-vertical-default-link-color: var(--on-frame);
  --installa-navbar-vertical-default-link-hover-color: var(--on-frame);
  --installa-navbar-vertical-default-link-active-color: var(--on-frame);
  --installa-navbar-vertical-default-label-color: var(--frame-label);
  --installa-navbar-vertical-default-hr-color: var(--frame-rule);
}

/* iOS and iPadOS Safari ignore a fixed background: there the bar draws the gradient across its own box, which on an
   iPad in landscape (1200px and up, sidebar beside it) is a slightly different slice of the same blue */
[data-look="app"] .navbar-top {
  background: var(--top-bar);
  background-attachment: fixed;
}

[data-look="app"] .navbar-top.navbar-glass-shadow {
  box-shadow: var(--frame-scrolled-shadow) !important;
}

/* The collapsed sidebar, opened by hovering: the sidebar's own paint (the canvas, or the frame choice's blue) */
[data-look="app"] .navbar-vertical-collapsed-hover .navbar-glass .navbar-vertical-content {
  background: var(--frame-side-overlay);
  background-attachment: fixed;
}

/* The sidebar's own colour runs the full height of the window behind the menu (desk widths, where the menu is a
   column). Transparent on the gradient; the frame choice's solid blue. */
@media (min-width: 1200px) {
  [data-look="app"] body:has(.navbar-vertical)::before {
    content: "";
    position: fixed;
    inset: 0 auto 0 0;
    width: 15.625rem;
    background: var(--frame-side);
    pointer-events: none;
  }
  [data-look="app"].navbar-vertical-collapsed body:has(.navbar-vertical)::before {
    width: 3.125rem;
  }
}

[data-look="app"] .navbar-vertical .nav-link,
[data-look="app"] .navbar-vertical .nav-link:hover,
[data-look="app"] .navbar-vertical .nav-link:focus {
  color: var(--on-frame);
  border-radius: var(--radius-sm);
}

[data-look="app"] .navbar-vertical .nav-link:hover {
  background-color: var(--frame-hover);
}

/** Hamburger menu button hover/focus states */
[data-look="app"] .navbar-toggler-humburger-icon.offcanvas-toggle:hover,
[data-look="app"] .navbar-toggler-humburger-icon.offcanvas-toggle:focus {
  background-color: var(--frame-hover) !important;
}

/* A journey's name over its links, in sentence case: never a small all-caps label (Joe, 15 Oct; D90) */
[data-look="app"] .navbar-vertical .navbar-nav .nav-item .navbar-vertical-label {
  color: var(--frame-label);
  font-size: var(--fs-12);
  font-weight: 600;
}

[data-look="app"] .navbar-vertical-divider,
[data-look="app"] .navbar-vertical .navbar-vertical-hr {
  border-color: var(--frame-rule);
  background-color: var(--frame-rule);
}

/* The page you are on: a lighter wash and bold, never a colour that fails on blue */
[data-look="app"] .navbar-vertical-content .nav-link.active {
  background-color: var(--frame-active);
}

[data-look="app"] .navbar-vertical-content .nav-link.active .nav-link-text,
[data-look="app"] .navbar-vertical-content .nav-link.active .nav-link-icon {
  color: var(--on-frame);
  font-weight: 700;
}

/* The top bar's icons (the hamburger, search on a phone, the bell) are white on the blue */
[data-look="app"] .navbar-top :is(.nav-link, .nav-link:hover, .nav-link:focus) {
  color: var(--on-top-bar);
}

[data-look="app"] .navbar-toggle-icon .toggle-line,
[data-look="app"] .navbar-toggle-icon::before,
[data-look="app"] .navbar-toggle-icon::after {
  background-color: var(--on-top-bar);
}

/* Under 1200px the top bar and the menu that drops from it are one solid blue, the same scrolled or not, and the
   menu's text is white on it */
@media (max-width: 1199px) {
  [data-look="app"] .navbar-vertical {
    --installa-navbar-vertical-default-link-color: var(--on-frame-solid);
    --installa-navbar-vertical-default-link-hover-color: var(--on-frame-solid);
    --installa-navbar-vertical-default-link-active-color: var(--on-frame-solid);
    --installa-navbar-vertical-default-label-color: var(--frame-solid-label);
    --installa-navbar-vertical-default-hr-color: var(--frame-solid-active);
  }
  [data-look="app"] :is(.navbar-vertical .navbar-collapse, .navbar-top),
  [data-look="app"] .navbar-vertical-collapsed-hover .navbar-glass .navbar-vertical-content {
    background: var(--frame-solid);
  }
  [data-look="app"] .navbar-vertical :is(.navbar-vertical-content, .nav-link, .nav-link:hover, .nav-link:focus),
  [data-look="app"] .navbar-vertical-content .nav-link.active :is(.nav-link-text, .nav-link-icon) {
    color: var(--on-frame-solid);
  }
  [data-look="app"] .navbar-vertical .navbar-nav .nav-item .navbar-vertical-label {
    color: var(--frame-solid-label);
  }
  [data-look="app"] .navbar-vertical-content .nav-link.active {
    background-color: var(--frame-solid-active);
  }
  [data-look="app"] .navbar-vertical-divider,
  [data-look="app"] .navbar-vertical .navbar-vertical-hr {
    border-color: var(--frame-solid-active);
    background-color: var(--frame-solid-active);
  }
}

/* ---- The admin panel and the designer and map screens: as before ticket 0107 ---------------------------------- */
[data-look="legacy"] .navbar-glass-shadow {
  background-color: rgba(59, 130, 211, 0.95);
}

[data-look="legacy"] .navbar-vertical-collapsed-hover .navbar-glass .navbar-vertical-content {
  background-color: rgba(59, 130, 211, 0.95);
}

[data-look="legacy"] .navbar-toggler-humburger-icon.offcanvas-toggle:hover,
[data-look="legacy"] .navbar-toggler-humburger-icon.offcanvas-toggle:focus {
  background-color: rgba(255, 255, 255, 0.2) !important;
}

[data-look="legacy"] .navbar-toggler-humburger-icon.offcanvas-toggle:hover {
  outline: 1px solid white;
}

[data-look="legacy"] .navbar-vertical .navbar-nav .nav-item .navbar-vertical-label {
  color: var(--installa-info);
}

[data-look="legacy"] .navbar-vertical-content .nav-link.active .nav-link-text,
[data-look="legacy"] .navbar-vertical-content .nav-link.active .nav-link-icon {
  color: var(--installa-warning);
  font-weight: bold;
}

[data-look="legacy"] .navbar-toggle-icon .toggle-line,
[data-look="legacy"] .navbar-toggle-icon::before,
[data-look="legacy"] .navbar-toggle-icon::after {
  background-color: var(--installa-gray-500);
}

/* The scrolled top bar took the body colour (the calendar fix, below, before ticket 0107) */
[data-look="legacy"] .navbar-top.navbar-glass.navbar-glass-shadow {
  background-color: var(--installa-body-bg, #3b82d3);
}

@media (max-width: 1199px) {
  [data-look="legacy"] :is(.navbar-vertical .navbar-collapse, .navbar-top) {
    background-color: rgba(40, 90, 145, 0.96);
  }
}



/* ---- Global search: the top bar's search (x-general.global-search around livewire:search-top) -------------------
   On a desk the field grows into the bar's free space, up to 560px, and never below 240px, so "+ New", the bell and
   the avatar keep their room. Under 992px it is an icon that opens the field across the whole top bar. White field,
   dark text: the placeholder is --text-muted on white (7.6:1); focus draws a white ring that shows on the blue. */
.global-search {
  flex: 1 1 35rem;
  min-width: 15rem;
  max-width: 35rem;
  margin-right: var(--space-4);
}

.global-search__trigger,
.global-search__close {
  display: none;
}

.global-search__box {
  position: relative;
}

.global-search__field {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 2.5rem;
  margin: 0;
  border: 1px solid var(--border-control);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
}

.global-search__field:focus-within {
  border-color: var(--brand);
  outline: 2px solid var(--on-top-bar);
  outline-offset: 2px;
}

.global-search__icon {
  position: absolute;
  left: var(--space-3);
  color: var(--text-muted);
  font-size: var(--fs-14);
  pointer-events: none;
}

.global-search__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 2.375rem;
  padding: 0 var(--space-2) 0 2.25rem;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--fs-14);
  -webkit-appearance: none;
  appearance: none;
}

.global-search__input::placeholder {
  color: var(--text-muted);
  opacity: 1;
}

.global-search__input::-webkit-search-cancel-button,
.global-search__input::-webkit-search-decoration {
  display: none;
  -webkit-appearance: none;
}

/* The "/" hint shows in the empty field until it has focus; the clear button once something is typed */
.global-search__kbd {
  min-width: 1.5rem;
  margin-right: var(--space-2);
  padding: 0 var(--space-2);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  box-shadow: none;
  color: var(--text-muted);
  font-family: var(--font-ui);
  font-size: var(--fs-12);
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
}

.global-search__input:focus ~ .global-search__kbd,
.global-search__input:not(:placeholder-shown) ~ .global-search__kbd {
  display: none;
}

.global-search__clear {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  margin-right: var(--space-1);
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
}

.global-search__clear:hover {
  background: var(--surface-page);
  color: var(--text);
}

.global-search__clear:focus-visible {
  outline: 2px solid var(--brand);
}

.global-search__input:not(:placeholder-shown) ~ .global-search__clear {
  display: inline-flex;
}

.global-search__results {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  right: 0;
  width: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--elev-1);
  color: var(--text);
}

.global-search__list {
  max-height: 24rem;
  padding: var(--space-2) 0;
  overflow-y: auto;
}

.global-search__results .dropdown-header {
  padding: var(--space-2) var(--space-4) var(--space-1);
  color: var(--text-muted);
  font-size: var(--fs-12);
  font-weight: 600;
}

.global-search__none {
  padding: var(--space-4);
  text-align: center;
}

.global-search__all {
  padding: var(--space-2);
  border-top: 1px solid var(--border);
  font-size: var(--fs-14);
  text-align: center;
}

@media (max-width: 991.98px) {
  /* The icon sits with the bell and the avatar */
  .global-search {
    flex: 0 0 auto;
    order: 2;
    min-width: 0;
    max-width: none;
    margin: 0 0 0 auto;
  }
  .navbar-top .global-search ~ .navbar-nav-icons {
    order: 3;
    margin-left: 0 !important;
  }
  .global-search__trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    min-height: 2.5rem;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--on-top-bar);
    font-size: var(--fs-20);
  }
  .global-search__panel {
    display: none;
  }
  /* Open: the field across the whole top bar, Close beside it */
  .global-search.is-open .global-search__panel {
    position: fixed;
    inset: 0 0 auto 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--installa-top-nav-height, 4.3125rem);
    padding: 0 var(--space-4);
    background: var(--frame-solid);
  }
  .global-search.is-open .global-search__box {
    flex: 1 1 auto;
    min-width: 0;
  }
  .global-search__input {
    font-size: var(--fs-16); /* 16px keeps a phone from zooming in on the field */
  }
  .global-search__kbd {
    display: none;
  }
  .global-search.is-open .global-search__close {
    display: inline-flex;
    align-items: center;
    min-height: 2.5rem;
    padding: 0 var(--space-2);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--on-frame-solid);
    font-weight: 600;
  }
  .global-search__close:focus-visible {
    outline: 2px solid var(--on-frame-solid);
  }
}



/* White text on the canvas is Joe's exception to 4.5:1 (tokens.css): small text written straight on it is 600 weight.
   A list's page-size picker sits on a white chip with dark text. */
[data-look="app"] :is(.app-breadcrumbs, .app-breadcrumbs a, .footer, .text-on-canvas-muted, .page-header__subtitle, .dashboard-intro p, .dashboard-quick-actions > .text-muted) {
  font-weight: 600;
}

[data-look="app"] .pagination-bar form {
  padding: 0 0 0 var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--surface);
}

[data-look="app"] .pagination-bar form label {
  color: var(--text);
}

/* ==========================================================================
   2. TYPOGRAPHY - Extended Font Sizes
   ========================================================================== */

/**
 * Extended Bootstrap font-size scale (fs-7 through fs-11)
 * Uses 1.2x ratio scale similar to Bootstrap's default
 * Usage: class="fs-8" for 1.2rem text
 */
.fs-11 {
  font-size: 0.6944444444rem !important;
}

.fs-10 {
  font-size: 0.8333333333rem !important;
}

.fs-9 {
  font-size: 1rem !important;
}

.fs-8 {
  font-size: 1.2rem !important;
}

.fs-7 {
  font-size: 1.44rem !important;
}

.fs-6 {
  font-size: 1.728rem !important;
}

.fs-5 {
  font-size: 2.0736rem !important;
}

.fs-4 {
  font-size: 2.48832rem !important;
}

.fs-3 {
  font-size: 2.985984rem !important;
}

.fs-2 {
  font-size: 3.5831808rem !important;
}

.fs-1 {
  font-size: 4.29981696rem !important;
}


/* ==========================================================================
   3. PAGE BACKGROUND
   ========================================================================== */

/** The canvas: Joe's choice 2 (tokens.css --canvas). The gradient by default; light grey with data-canvas="frame". */
body {
  background: var(--canvas-flat);
  background: var(--canvas);
  background-attachment: fixed;
}

/* The admin panel and the designer keep the theme's own background */
[data-look="legacy"] body {
  background: linear-gradient(90deg, rgba(59, 130, 211, 1) 0%, rgba(71, 145, 230, 1) 35%, rgba(49, 114, 197, 1) 100%);
}


/* ==========================================================================
   4. FORM HELPERS
   ========================================================================== */

/** Hide help text until hover for cleaner forms */
.form-group small.text-muted {
  visibility: hidden;
}

.form-group:hover small.text-muted {
  visibility: visible;
}


/* ==========================================================================
   5. UTILITY CLASSES
   ========================================================================== */

/** Large icon for empty states and hero sections */
.icon-giant {
  font-size: 5em;
}

/** Report container styling */
.report {
  padding: 1em;
  border: 1px solid #ccc;
  border-radius: 0.5em;
}

/** Code block styling (dark theme) */
pre:has(> code) {
  padding: 1em;
  background-color: rgba(0, 0, 0, 0.9);
  color: #f7f7f7;
}

/** Right-aligned action bar */
.actionbar {
  text-align: right;
}


/** Fixed height image for consistent card layouts */
.fixed-height-img {
  height: 240px;
  object-fit: cover;
  width: 100%;
}


/* ==========================================================================
   6. CARD VARIANTS
   ========================================================================== */

/** Comment card: Remove bottom margin from last paragraph */
.comment .card-body p:last-child {
  margin-bottom: 0;
}

/** Google Map container within supermap component */
.supermap .googlemap {
  width: 100%;
  height: 600px;
}

/** Overdue customer row: a waiting tint */
.summary-customer .overdue {
  background-color: var(--chip-wait-bg);
}

/** Lead score badge styling */
.badge.score {
  font-size: 150%;
  margin-left: 3px;
}

.badge.triage:has(span) {
  padding-right: 0px;
}

.card-header {
  padding: 0.75rem 0.75rem;
}

.project-tabs {
  padding: 0;
}

.project-tabs .nav-tabs {
  background-color: var(--surface);
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
}

.project-tabs .nav-tabs .nav-link {
  padding: 0.75rem 0.75rem;
  color: var(--text-muted);
  border: 0;
}

.project-tabs .nav-tabs .nav-link.active {
  color: var(--text);
  font-weight: 600;
  background: transparent;
  box-shadow: inset 0 -2px 0 var(--brand);
}


/* ==========================================================================
   7. TEXT ON SURFACES AND ON THE CANVAS (ticket 0107)
   ========================================================================== */

/**
 * Text has one colour per place it sits, never one it inherits by luck. On a white surface (a card, a menu, a
 * modal, a row) it is --text; directly on the canvas (page titles, breadcrumbs) it is --on-canvas. The old
 * white-on-glass inheritance is gone: a card is white, so what is in it is dark.
 */
[data-look="app"] :is(.card, .modal-content, .dropdown-menu, .popover, .list-group-item, .accordion-body, .table, .settings-note, .bg-light, .bg-white, .toast:not([class*="bg-"])) {
  color: var(--text);
}

/* The theme gives these components the body colour, which is the canvas's white: on their white surfaces they read
   --text, and a hovered list item is a pale grey, not the canvas blue */
[data-look="app"] .table {
  --installa-table-hover-color: var(--text);
  --installa-table-active-color: var(--text);
}

[data-look="app"] .list-group {
  --installa-list-group-action-hover-bg: var(--surface-page);
  --installa-list-group-action-active-color: var(--text);
}

[data-look="app"] :is(.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm) {
  --installa-offcanvas-color: var(--text);
}

[data-look="app"] .accordion {
  --installa-accordion-color: var(--text);
}

/* Text written on the canvas itself. Use these rather than text-white, so the canvas choice stays one rule. */
.text-on-canvas {
  color: var(--on-canvas) !important;
}

.text-on-canvas-muted,
.text-on-canvas .text-mid,
.text-on-canvas .text-light,
.page-header .page-header__title .text-mid {
  color: var(--on-canvas-muted) !important;
}

/* A link written on the canvas (a page title's "for Contact 1") is canvas-coloured and underlined: brand blue on
   the blue gradient would vanish */
:is(.page-header, .text-on-canvas) a:not(.btn):not(.badge) {
  color: var(--on-canvas);
  text-decoration: underline;
}

/* The same markup inside a white surface (a section heading in a card) reads dark */
:is(.card, .modal-content) .text-on-canvas {
  color: var(--text) !important;
}

:is(.card, .modal-content) .text-on-canvas a:not(.btn):not(.badge) {
  color: var(--link);
}

:is(.card, .modal-content) :is(.text-on-canvas .text-mid, .text-on-canvas-muted) {
  color: var(--text-muted) !important;
}

/* Help under a field: the theme's #9da9bb is 2.6:1 on white */
[data-look="app"] .form-text {
  color: var(--text-muted);
}

/* The admin panel and the designer keep the theme's rules (white canvas text, dark text in cards) */
[data-look="legacy"] :is(.card-body, .card-footer, .modal-body, .modal-footer, .table, .list-group-item, .accordion-body, .alert, label) {
  color: #344050;
}



/* ==========================================================================
   8. BUTTON ROLES AND STATE CHIPS (ticket 0107)
   Primary: .btn-primary, the one thing to press: --action (brand yellow) with --on-action (dark) text.
   Secondary: .btn-success, solid green with white text (--action-2).
   Tertiary: every outline, light, secondary and Falcon default button: white with a border and dark text.
   Danger and warning keep their meaning in red and amber. No hover lift: hover changes the colour only.
   .look-roles gives a block on a legacy screen (the map's card, the designer's actions) the same roles (ticket 0116).
   ========================================================================== */

:is([data-look="app"], .look-roles) .btn {
  border-radius: var(--radius-sm);
  font-weight: 600;
  box-shadow: none;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

:is([data-look="app"], .look-roles) .btn-primary {
  --installa-btn-color: var(--on-action);
  --installa-btn-bg: var(--action);
  --installa-btn-border-color: var(--action);
  --installa-btn-hover-color: var(--on-action);
  --installa-btn-hover-bg: var(--action-hover);
  --installa-btn-hover-border-color: var(--action-hover);
  --installa-btn-focus-shadow-rgb: 245, 166, 35;
  --installa-btn-active-color: var(--on-action);
  --installa-btn-active-bg: var(--action-hover);
  --installa-btn-active-border-color: var(--action-hover);
  --installa-btn-disabled-color: var(--on-action);
  --installa-btn-disabled-bg: var(--action);
  --installa-btn-disabled-border-color: var(--action);
}

:is([data-look="app"], .look-roles) .btn-success {
  --installa-btn-color: var(--on-action-2);
  --installa-btn-bg: var(--action-2);
  --installa-btn-border-color: var(--action-2);
  --installa-btn-hover-color: var(--on-action-2);
  --installa-btn-hover-bg: var(--action-2-hover);
  --installa-btn-hover-border-color: var(--action-2-hover);
  --installa-btn-focus-shadow-rgb: 21, 128, 61;
  --installa-btn-active-color: var(--on-action-2);
  --installa-btn-active-bg: var(--action-2-hover);
  --installa-btn-active-border-color: var(--action-2-hover);
  --installa-btn-disabled-color: var(--on-action-2);
  --installa-btn-disabled-bg: var(--action-2);
  --installa-btn-disabled-border-color: var(--action-2);
}

[data-look="app"] .btn-default,
[data-look="app"] .btn-tertiary,
[data-look="app"] .btn-falcon-default,
[data-look="app"] .btn-outline-primary,
[data-look="app"] .btn-outline-secondary,
[data-look="app"] .btn-outline-success,
[data-look="app"] .btn-outline-info,
[data-look="app"] .btn-outline-light,
[data-look="app"] .btn-outline-dark {
  --installa-btn-color: var(--text);
  --installa-btn-bg: var(--surface);
  --installa-btn-border-color: var(--border-control);
  --installa-btn-hover-color: var(--text);
  --installa-btn-hover-bg: var(--surface-page);
  --installa-btn-hover-border-color: var(--text-muted);
  --installa-btn-focus-shadow-rgb: 21, 107, 166;
  --installa-btn-active-color: var(--text);
  --installa-btn-active-bg: var(--border);
  --installa-btn-active-border-color: var(--text-muted);
  --installa-btn-disabled-color: var(--text-muted);
  --installa-btn-disabled-bg: var(--surface);
  --installa-btn-disabled-border-color: var(--border-control);
  background-color: var(--installa-btn-bg);
  border-color: var(--installa-btn-border-color);
  color: var(--installa-btn-color);
}

[data-look="app"] :is(.btn-default, .btn-tertiary, .btn-falcon-default, .btn-outline-primary, .btn-outline-secondary, .btn-outline-success, .btn-outline-info, .btn-outline-light, .btn-outline-dark):is(:hover, :focus-visible, .show) {
  background-color: var(--installa-btn-hover-bg);
  border-color: var(--installa-btn-hover-border-color);
  color: var(--installa-btn-hover-color);
}

/* The chosen one of a set (List / Board, a filter): an info tint, so "on" never looks like "hovered" */
[data-look="app"] :is(.btn-default, .btn-tertiary, .btn-falcon-default, .btn-outline-primary, .btn-outline-secondary, .btn-outline-success, .btn-outline-info, .btn-outline-light, .btn-outline-dark):is(.active, [aria-current="page"]) {
  background-color: var(--chip-info-bg);
  border-color: var(--brand);
  color: var(--chip-info);
}

/* A filled neutral: the "on" state of a toggle drawn as btn-secondary / btn-light beside outline buttons */
[data-look="app"] .btn-secondary,
[data-look="app"] .btn-light {
  --installa-btn-color: var(--chip-neutral);
  --installa-btn-bg: var(--chip-neutral-bg);
  --installa-btn-border-color: var(--border-control);
  --installa-btn-hover-color: var(--text);
  --installa-btn-hover-bg: var(--border-control);
  --installa-btn-hover-border-color: var(--text-muted);
  --installa-btn-active-color: var(--text);
  --installa-btn-active-bg: var(--border-control);
  --installa-btn-active-border-color: var(--text-muted);
  --installa-btn-disabled-color: var(--chip-neutral);
  --installa-btn-disabled-bg: var(--chip-neutral-bg);
  --installa-btn-disabled-border-color: var(--border-control);
}

[data-look="app"] .btn-outline-danger,
[data-look="app"] .btn-outline-warning {
  --installa-btn-bg: var(--surface);
  --installa-btn-hover-color: var(--installa-btn-color);
  --installa-btn-active-color: var(--installa-btn-color);
  background-color: var(--surface);
}

[data-look="app"] .btn-outline-danger {
  --installa-btn-color: var(--bad);
  --installa-btn-border-color: var(--bad);
  --installa-btn-hover-bg: var(--chip-problem-bg);
  --installa-btn-hover-border-color: var(--bad);
  --installa-btn-active-bg: var(--chip-problem-bg);
}

[data-look="app"] .btn-outline-warning {
  --installa-btn-color: var(--wait);
  --installa-btn-border-color: var(--wait);
  --installa-btn-hover-bg: var(--chip-wait-bg);
  --installa-btn-hover-border-color: var(--wait);
  --installa-btn-active-bg: var(--chip-wait-bg);
}

[data-look="app"] .btn-danger,
[data-look="app"] .btn-warning,
[data-look="app"] .btn-info {
  --installa-btn-color: #fff;
  --installa-btn-hover-color: #fff;
  --installa-btn-active-color: #fff;
}

[data-look="app"] .btn-danger {
  --installa-btn-bg: var(--bad);
  --installa-btn-border-color: var(--bad);
  --installa-btn-hover-bg: var(--chip-problem);
  --installa-btn-hover-border-color: var(--chip-problem);
  --installa-btn-active-bg: var(--chip-problem);
}

[data-look="app"] .btn-warning {
  --installa-btn-bg: var(--wait);
  --installa-btn-border-color: var(--wait);
  --installa-btn-hover-bg: var(--chip-wait);
  --installa-btn-hover-border-color: var(--chip-wait);
  --installa-btn-active-bg: var(--chip-wait);
}

[data-look="app"] .btn-info {
  --installa-btn-bg: var(--info);
  --installa-btn-border-color: var(--info);
  --installa-btn-hover-bg: var(--brand-strong);
  --installa-btn-hover-border-color: var(--brand-strong);
  --installa-btn-active-bg: var(--brand-strong);
}

[data-look="app"] .btn-link {
  --installa-btn-color: var(--link);
  --installa-btn-hover-color: var(--link-hover);
}

/* Disabled is the one state that may look switched off, so it must look different from a tertiary button: faded,
   no fill. */
[data-look="app"] .btn:is(:disabled, .disabled),
[data-look="app"] fieldset:disabled .btn {
  opacity: 0.45;
  box-shadow: none;
  cursor: not-allowed;
}

[data-look="app"] :is([class*="btn-outline-"], .btn-light):is(:disabled, .disabled) {
  background-color: transparent;
}

/* State chips: five tints, dark text on each (tokens.css --chip-*). A badge's colour is a state, never decoration:
   done, waiting, problem, info, neutral. A badge painted with a stage's own colour (inline style) keeps it. */
[data-look="app"] .badge {
  border-radius: var(--radius-sm);
  font-weight: 600;
}

[data-look="app"] .badge:is(.bg-success, .badge-subtle-success) {
  background-color: var(--chip-done-bg) !important;
  color: var(--chip-done) !important;
}

[data-look="app"] .badge:is(.bg-warning, .badge-subtle-warning) {
  background-color: var(--chip-wait-bg) !important;
  color: var(--chip-wait) !important;
}

[data-look="app"] .badge:is(.bg-danger, .badge-subtle-danger) {
  background-color: var(--chip-problem-bg) !important;
  color: var(--chip-problem) !important;
}

[data-look="app"] .badge:is(.bg-info, .bg-primary, .badge-subtle-info, .badge-subtle-primary) {
  background-color: var(--chip-info-bg) !important;
  color: var(--chip-info) !important;
}

[data-look="app"] .badge:is(.bg-secondary, .bg-light, .badge-subtle-secondary, .badge-subtle-light) {
  background-color: var(--chip-neutral-bg) !important;
  color: var(--chip-neutral) !important;
}

[data-look="app"] .badge :is(.text-white, .text-dark) {
  color: inherit !important;
}

/* A task row's title is a line in a list, not a heading */
.summary-task .summary-title.task-title {
  font-size: 1rem;
  line-height: 1.3;
}


/* ==========================================================================
   9. FORM INPUT ADJUSTMENTS
   ========================================================================== */

/** More vertical, less horizontal padding for inputs */
.form-control,
.form-select {
  padding: 0.5rem 0.5rem;
  border: 1px solid var(--border-control);
  border-radius: var(--radius-sm);
}


/* ==========================================================================
   6 / 10. CARD SURFACES (ticket 0107)
   One card: white, a hairline border, radius 8, no shadow (elevation 0). .card-glass, .card-clear and .card-solid
   are kept as names so old markup draws the same card; there is no frosted glass and no backdrop blur.
   ========================================================================== */

[data-look="app"] .card,
[data-look="app"] .card:is(.card-glass, .card-clear, .card-solid) {
  --installa-card-bg: var(--surface);
  --installa-card-border-width: 1px;
  --installa-card-border-color: var(--border);
  --installa-card-border-radius: var(--radius);
  --installa-card-inner-border-radius: calc(var(--radius) - 1px);
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--elev-0);
}

[data-look="app"] .card:not([class*="bg-"]) > :is(.card-header, .card-body, .card-footer) {
  background-color: var(--surface);
}

[data-look="app"] .card > :is(.card-header, .card-body):first-child {
  border-top-left-radius: inherit;
  border-top-right-radius: inherit;
}

[data-look="app"] .card > :is(.card-body, .card-footer):last-child {
  border-bottom-left-radius: inherit;
  border-bottom-right-radius: inherit;
}

[data-look="app"] .card > .card-header {
  border-bottom: 1px solid var(--border);
}

[data-look="app"] .card > .card-footer {
  border-top: 1px solid var(--border);
}

/* A solid coloured header covers the card's hairline (ticket 0114; a tint keeps it): the border used to show as a thin white frame round the
   colour. It sits over the card's own border on three sides, and needs no line under it. */
[data-look="app"] .card > .card-header:is(.panel-header--entity, .bg-primary, .bg-secondary, .bg-success, .bg-info, .bg-warning, .bg-danger, .bg-dark):not([class*="bg-opacity"]) {
  margin: -1px -1px 0;
  border-bottom-color: transparent;
  border-top-left-radius: var(--radius);
  border-top-right-radius: var(--radius);
}
/* With nothing under it (a folded panel, or a header alone) it covers the card's bottom too and rounds all four
   corners. Folded is read from the body (.collapse without .show) and from the toggle, so either way of folding counts. */
[data-look="app"] .card > .card-header:is(.panel-header--entity, .bg-primary, .bg-secondary, .bg-success, .bg-info, .bg-warning, .bg-danger, .bg-dark):not([class*="bg-opacity"]):is(:last-child, :has(+ .collapse:not(.show)), :has(.panel-header__toggle[aria-expanded="false"])) {
  margin-bottom: -1px;
  border-bottom-left-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
}

/* ==========================================================================
   11. TABLE STYLES
   ========================================================================== */

/** Large row variant for emphasis */
tr.bigrow {
  font-size: 150%;
}


/* ==========================================================================
   12. DEVELOPMENT HELPERS
   ========================================================================== */

/**
 * Visual indicator for work-in-progress features
 * Usage: <div class="card development-placeholder">
 */
.development-placeholder {
  opacity: 0.9;
  outline: 1px dashed red;
  box-shadow: inset 0 0 10px 10px rgba(255, 0, 0, 0.5);
}


/* ==========================================================================
   13. USER BADGE COMPONENT
   ========================================================================== */

/**
 * Compact user display with avatar
 * Usage: <span class="user-badge"><img src="avatar.jpg"><span>Name</span></span>
 */
.user-badge {
  display: inline-block;
  padding: 2px;
  border: 1px solid #eee;
  background: #fff;
  color: #111;
  border-radius: 24px;
  text-align: left;
  min-width: 160px;
}

.user-badge span {
  padding: 0 10px 0 0;
}

.user-badge img {
  width: 32px;
  height: 32px;
  margin-right: 8px;
  border-radius: 16px;
}

.user-badge:hover {
  background-color: #106DB8;
}

.user-badge:hover span {
  color: #fff;
}


/* ==========================================================================
   14. CONTENT EDITABLE STYLES
   ========================================================================== */

/** Remove default outline for contenteditable elements */
[contenteditable] {
  outline: 0px solid transparent;
}

/** Visual indicator when editing inline content */
.editing {
  outline: 5px dashed rgba(252, 151, 0, 0.9);
}


/* ==========================================================================
   15. NOTEBOARD COMPONENT
   ========================================================================== */

/**
 * The sticky note on a customer: a yellow tint from the tokens, at the body size (ticket 0176). It used to be its own
 * hex yellow at 22px, so on a phone one line of note filled the screen.
 */
.noteboard {
  padding: var(--space-3) var(--space-4);
  font-size: var(--installa-body-font-size);
  line-height: 1.5;
  color: var(--text);
  background: var(--chip-wait-bg);
  border: 1px solid var(--border);
}

/** Noteboard empty state - compact with placeholder */
.noteboard .editable-content:empty::before {
  content: "Sticky note — access codes, \"call after 6pm\", anything the team should see at a glance. Click the pen to add one.";
  color: var(--chip-wait);
  font-size: var(--fs-12);
  font-style: italic;
}
.noteboard:has(.editable-content:empty) {
  padding: var(--space-2) var(--space-4);
}

/** Noteboard while it is being written: the action colour round it, never a coloured left edge */
.noteboard.editing {
  background-color: var(--action-tint);
  outline: 2px solid var(--action);
  outline-offset: -2px;
}

/* The history's delete (ticket 0176): always shown on a touch screen, which has no hover; on hover where there is a mouse */
.activity-feed .timeline-delete {
  opacity: 0.7;
}
@media (hover: hover) and (pointer: fine) {
  .activity-feed .timeline-delete {
    opacity: 0;
    transition: opacity 0.2s ease;
  }
  .activity-feed .timeline-item:hover .timeline-delete,
  .activity-feed .timeline-delete:focus-visible {
    opacity: 0.7;
  }
  .activity-feed .timeline-delete:hover {
    opacity: 1;
  }
}


/* ==========================================================================
   15b. THE DESIGNER'S FIRST MINUTE (ticket 0117)
   The summary card on the canvas (screens/parts/designer-summary.blade.php): top right under the settings cog on a
   desk, across the top beside the tools on a phone. One white card; its buttons take the action roles (.look-roles).
   The settings drawer folds its render and debug settings under Advanced.
   ========================================================================== */
#canvasWrapper .designer-summary {
  position: absolute;
  top: 60px;
  right: 10px;
  bottom: auto;
  z-index: 104;
  width: 17.5rem;
  height: auto;
  margin: 0;
  padding: 0;
  border-radius: var(--radius);
  box-shadow: var(--elev-1);
  font-family: var(--font-ui);
}
#canvasWrapper .designer-summary .card-body { padding: var(--space-3) var(--space-4); }
.designer-summary__figures {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2) var(--space-3);
  margin: 0;
}
.designer-summary__figures > div { display: flex; flex-direction: column-reverse; }
.designer-summary__figures dt {
  font-size: var(--fs-12);
  font-weight: 400;
  color: var(--text-muted);
}
.designer-summary__figures dd {
  margin: 0;
  font-size: var(--fs-20);
  line-height: var(--lh-tight);
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.designer-summary__basis {
  margin: var(--space-2) 0 0;
  font-size: var(--fs-12);
  color: var(--text-muted);
}
/* The hills around (ticket 0124): a quiet loading line and the terrain's source, in the canvas's bottom corners */
#canvasWrapper .designer-terrain-status,
#canvasWrapper .designer-attribution {
  position: absolute;
  bottom: var(--space-2);
  z-index: 103;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.82);
  color: var(--text-muted);
  font-family: var(--font-ui);
  font-size: var(--fs-12);
  pointer-events: none;
}
#canvasWrapper .designer-terrain-status { left: var(--space-2); }
#canvasWrapper .designer-attribution { right: var(--space-2); max-width: 60%; }
#canvasWrapper .designer-terrain-status[hidden],
#canvasWrapper .designer-attribution[hidden] { display: none; }
/* The hills around (ticket 0124): its own line, reserved from the start so the card never grows when it fills */
.designer-summary__hills {
  display: block;
  min-height: 1.5em;
}
.designer-summary__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.designer-summary__actions .btn { flex: 1 1 auto; }
.designer-summary__actions #layoutAgainBtn { flex-basis: 100%; }
.designer-summary .btn-outline-secondary {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border-control);
}
.designer-summary .btn-outline-secondary:hover { background: var(--surface-sunken); color: var(--text); }

#settingsMenu .designer-settings__value { min-width: 3.5rem; text-align: right; }
#settingsMenu .designer-advanced {
  border-top: 1px solid rgba(255, 255, 255, 0.25);
  padding-top: var(--space-3);
}
#settingsMenu .designer-advanced > summary { cursor: pointer; }

@media (max-width: 576px) {
  #canvasWrapper .designer-summary {
    top: 56px;
    left: 80px;
    right: 8px;
    width: auto;
  }
  #canvasWrapper .designer-summary .card-body { padding: var(--space-2) var(--space-3); }
  .designer-summary__figures { grid-template-columns: repeat(4, auto); gap: var(--space-1) var(--space-2); }
  .designer-summary__figures dd { font-size: var(--fs-16); }
  .designer-summary__actions { margin-top: var(--space-2); }
  .designer-summary__actions .btn { padding: var(--space-1) var(--space-2); }
}

/* ==========================================================================
   16. ADDRESS/MAP STYLES
   ========================================================================== */

/** Responsive address map image */
.address-map {
  max-width: 100%;
  height: auto;
  margin: 0 auto;
  max-height: 240px;
  width: 100%;
}


/* ==========================================================================
   17. FORM HELP BLOCKS
   ========================================================================== */

/** Help text below form inputs - hidden until hover */
.main-form-area .help-block {
  font-size: 14px;
  line-height: 16px;
  margin-top: 2px;
  margin-bottom: 0;
  padding: 0;
  opacity: 0;
}

.main-form-area input:hover+.help-block,
.main-form-area select:hover+.help-block,
.main-form-area textarea:hover+.help-block {
  opacity: 0.7;
  transition: opacity 0.3s ease-in-out;
}

/** Required field indicator (asterisk) */
.main-form-area .form-group .control-label sup {
  font-size: 18px;
  color: #FF9719;
  line-height: 80%;
}


/* ==========================================================================
   18. SCROLLBAR STYLES
   ========================================================================== */

/**
 * Thin, themed scrollbars for all scrollable elements
 * (textareas, dropdowns, modals, kanban columns, etc.)
 * The main page body scrollbar is handled by OverlayScrollbars in scrollbar.js
 */
*,
*::before,
*::after {
  scrollbar-width: thin;
  scrollbar-color: rgba(59, 130, 211, 0.4) transparent;
}


/* ==========================================================================
   19. CURSOR UTILITIES
   ========================================================================== */

/**
 * Cursor utility classes for interactive elements
 * Usage: <div class="grab"> for grab cursor on hover
 */
.alias {
  cursor: alias;
}

.all-scroll {
  cursor: all-scroll;
}

.auto {
  cursor: auto;
}

.cell {
  cursor: cell;
}

.col-resize {
  cursor: col-resize;
}

.context-menu {
  cursor: context-menu;
}

.copy {
  cursor: copy;
}

.crosshair {
  cursor: crosshair;
}

.default {
  cursor: default;
}

.e-resize {
  cursor: e-resize;
}

.ew-resize {
  cursor: ew-resize;
}

.grab {
  cursor: -webkit-grab;
  cursor: grab;
}

.grabbing {
  cursor: -webkit-grabbing;
  cursor: grabbing;
}

.help {
  cursor: help;
}

.move {
  cursor: move;
}

.n-resize {
  cursor: n-resize;
}

.ne-resize {
  cursor: ne-resize;
}

.nesw-resize {
  cursor: nesw-resize;
}

.ns-resize {
  cursor: ns-resize;
}

.nw-resize {
  cursor: nw-resize;
}

.nwse-resize {
  cursor: nwse-resize;
}

.no-drop {
  cursor: no-drop;
}

.none {
  cursor: none;
}

.not-allowed {
  cursor: not-allowed;
}

.pointer {
  cursor: pointer;
}

.progress {
  cursor: progress;
}

.row-resize {
  cursor: row-resize;
}

.s-resize {
  cursor: s-resize;
}

.se-resize {
  cursor: se-resize;
}

.sw-resize {
  cursor: sw-resize;
}

.text {
  cursor: text;
}

.w-resize {
  cursor: w-resize;
}

.wait {
  cursor: wait;
}

.zoom-in {
  cursor: zoom-in;
}

.zoom-out {
  cursor: zoom-out;
}

/* ==========================================================================
   20. BREADCRUMB / CONTEXT TRAIL (rendered by layouts/app from each
       screen's @section('breadcrumbs') via App\Support\Breadcrumbs)
   ========================================================================== */

.app-breadcrumbs {
  padding: 0.35rem 0 0.15rem;
  min-height: 1.9rem;
  font-size: 0.8125rem;
}

.app-breadcrumbs .app-breadcrumb {
  background: transparent;
  padding: 0;
}

/* Breadcrumbs read directly on the canvas: --on-canvas / --on-canvas-muted pass 4.5:1 on either canvas */
.app-breadcrumbs .breadcrumb-item,
.app-breadcrumbs .breadcrumb-item a {
  color: var(--on-canvas-muted);
  text-decoration: none;
}

.app-breadcrumbs .breadcrumb-item a:hover {
  color: var(--on-canvas);
  text-decoration: underline;
}

.app-breadcrumbs .breadcrumb-item.active,
.app-breadcrumbs .breadcrumb-item + .breadcrumb-item::before {
  color: var(--on-canvas);
}

.app-breadcrumbs .breadcrumb-item.active {
  font-weight: 600;
}

.app-breadcrumbs-help {
  color: var(--on-canvas-muted);
  font-size: 0.95rem;
  line-height: 1;
}

.app-breadcrumbs-help:hover,
.app-breadcrumbs-help:focus {
  color: var(--on-canvas);
}

/* ==========================================================================
   21. PROJECT LIFECYCLE TRACKER (livewire/projects/lifecycle-control,
       rendered inside the light project hero card)
   ========================================================================== */

.lifecycle-tracker {
  display: flex;
  align-items: flex-start;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: lifecycle;
}

.lifecycle-tracker__step {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  padding-top: 0.15rem;
}

.lifecycle-tracker__step::before {
  content: "";
  position: absolute;
  top: 0.95rem;
  left: 50%;
  right: -50%;
  height: 2px;
  background: rgba(15, 40, 80, 0.14);
}

.lifecycle-tracker__step:last-child::before {
  display: none;
}

.lifecycle-tracker__step.is-done::before {
  background: #2ecc71;
}

.lifecycle-tracker__dot {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  background: #fff;
  color: #6c7a8f;
  border: 2px solid rgba(15, 40, 80, 0.18);
}

.lifecycle-tracker__step.is-done .lifecycle-tracker__dot {
  background: #2ecc71;
  border-color: #2ecc71;
  color: #fff;
}

.lifecycle-tracker__step.is-current .lifecycle-tracker__dot {
  background: #0d6efd;
  border-color: #0d6efd;
  color: #fff;
  box-shadow: 0 0 0 4px rgba(13, 110, 253, 0.18);
}

.lifecycle-tracker__label {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.68rem;
  line-height: 1.15;
  color: #6c7a8f;
  padding: 0 0.15rem;
}

.lifecycle-tracker__step.is-current .lifecycle-tracker__label {
  color: #0d6efd;
  font-weight: 700;
}

.lifecycle-tracker__step.is-done .lifecycle-tracker__label {
  color: #2f3e55;
}

.lifecycle-tracker--parked {
  opacity: 0.55;
}

.lifecycle-control__menu {
  min-width: 17rem;
  max-height: 70vh;
  overflow-y: auto;
}

@media (max-width: 767.98px) {
  .lifecycle-tracker__label {
    display: none;
  }
}

/* ==========================================================================
   22. DISCOVERABLE UI: "+ New" button, screen tips, Today work queues,
       customer journey, workspace hint in the sidebar
   ========================================================================== */

/* "+ New" is the action colour: the one place to start anything */
.app-new-btn,
.app-new-btn:focus-visible,
.app-new-btn.show {
  padding: 0.25rem 0.85rem;
  border: 0;
  border-radius: var(--radius-sm);
  background-color: var(--action);
  color: var(--on-action);
}

.app-new-btn:hover {
  background-color: var(--action-hover);
  color: var(--on-action);
}

.app-tip {
  margin: 0.25rem 0 1rem;
  padding: 0.75rem 1rem;
  border-radius: 0.6rem;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}

/* "Got it" sets [hidden]; it must beat the tip's own d-flex (display:flex !important), which an inline display:none
   never did (0117 walk: no tip anywhere went away until the page was reloaded) */
.app-tip[hidden] {
  display: none !important;
}

/* The tip says what it is with its icon, not a coloured left edge (Joe, 7 Oct: no left-border accents) */
.app-tip__icon {
  color: var(--wait);
  font-size: 1.15rem;
  line-height: 1.4;
}

.app-tip__title {
  font-weight: 700;
  font-size: 0.9rem;
}

.app-tip__body {
  font-size: 0.85rem;
  line-height: 1.45;
}

.app-tip__close {
  font-size: 0.7rem;
  margin-top: 0.15rem;
}

/* A tip that opens as its title only (<x-general.tip collapsed>): the title is the button that opens the rest */
.app-tip--collapsible {
  padding: 0.5rem 0.85rem;
}

.app-tip__toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  text-align: left;
  line-height: 1.6;
}

.app-tip__chevron {
  margin-left: auto;
  font-size: 0.7rem;
  color: var(--text-mid);
  transition: transform 0.15s;
}

.app-tip__toggle[aria-expanded="true"] .app-tip__chevron {
  transform: rotate(180deg);
}

.app-tip__toggle + [id] {
  margin-top: 0.35rem;
}

/* Today queues (dashboard). The one card (ticket 0107): white, a hairline border, radius 8, no shadow; every colour a
   token (ticket 0145) */
.today-queues {
  align-items: flex-start;
}

.today-queue {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.today-queue__head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 0.9rem 0.4rem;
}

.today-queue__count {
  margin-left: auto;
  min-width: 1.9rem;
  text-align: center;
  border-radius: var(--radius-pill);
  font-weight: 700;
  font-size: 0.8rem;
  padding: 0.15rem 0.5rem;
}

.today-queue__title {
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--text);
}

.today-queue__list {
  list-style: none;
  margin: 0;
  padding: 0 0.4rem 0.4rem;
}

.today-queue__item {
  display: block;
  padding: 0.4rem 0.5rem;
  border-radius: var(--radius-sm);
  color: var(--text);
  text-decoration: none;
  line-height: 1.25;
}

.today-queue__item:hover {
  background: var(--surface-sunken);
  color: var(--link-hover);
}

.today-queue__item-title {
  font-size: 0.85rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Readable on a phone: never under 0.8rem (ticket 0145) */
.today-queue__item-meta {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.today-queue__empty {
  padding: 0.4rem 0.9rem 0.9rem;
  font-size: 0.8rem;
  color: var(--text-muted);
}

.today-queue__foot {
  padding: 0 0.9rem 0.3rem;
  font-size: 0.8rem;
}

/* A foot link is a 44 px tap target (ticket 0145) */
.today-queue__foot a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* Home: what was the page's own <style> block, on the tokens (ticket 0145) */
.dashboard-shell {
  color: var(--text);
}

.dashboard-intro,
.dashboard-intro h3 {
  color: var(--on-canvas);
  letter-spacing: 0.2px;
}

.dashboard-intro .text-muted {
  color: var(--on-canvas-muted) !important;
}

.dashboard-quick-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: 0.65rem 0.8rem;
  border-radius: var(--radius);
  background: var(--canvas-band);
}

.dashboard-quick-actions__label {
  color: var(--on-canvas);
  margin-right: var(--space-1);
}

/* On a phone the Start bar is the roof box only: "+ New" in the top bar starts anything else */
@media (max-width: 575.98px) {
  .dashboard-quick-actions .quick-action-btn,
  .dashboard-quick-actions__label {
    display: none !important;
  }
}

.dashboard-shell .card-header {
  padding: 0.4rem 0.75rem;
}

.dashboard-shell .list-group-item {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

/* Needs attention: the row wraps rather than squeezing its title behind the button */
.attention-row__body {
  min-width: 0;
  flex: 1 1 16rem;
}

.attention-row__go {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

/* Stage cards: a neutral chip with the stage's colour as a dot, so a yellow stage reads as well as a navy one */
.stage-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.stage-chip {
  flex: 1 1 100px;
  max-width: 160px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 5px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-sunken);
  color: var(--text);
  text-decoration: none;
}

.stage-chip:hover {
  border-color: var(--border-control);
  color: var(--text);
}

.stage-chip__count {
  font-size: var(--fs-20);
  font-weight: 700;
  line-height: var(--lh-tight);
}

.stage-chip__name {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-12);
  font-weight: 600;
  text-align: center;
}

.stage-chip__dot {
  width: 0.6rem;
  height: 0.6rem;
  flex: 0 0 auto;
}

.month-figure__note {
  font-size: var(--fs-12);
}

.week-day__count {
  width: 30px;
  height: 30px;
}

.week-day__today {
  color: var(--on-action);
}

.week-day__kinds {
  font-size: var(--fs-12);
}

/* A row worked where it sits (ticket 0144): the row's link, then its actions, each a 44 px tap target */
.today-queue__line {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.today-queue__line .today-queue__item {
  flex: 1 1 auto;
  min-width: 0;
}

.today-queue__actions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex: 0 0 auto;
  padding-right: var(--space-1);
}

.today-queue__action {
  min-height: 44px;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.today-queue__log {
  margin: 0 var(--space-2) var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

.today-queue__outcomes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  margin-bottom: var(--space-2);
  border: 0;
  padding: 0;
}

.today-queue__outcome {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 44px;
  font-size: var(--fs-14);
}

.today-queue__log-buttons {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.today-queue__done {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  min-height: 44px;
  font-size: var(--fs-14);
}

.today-queue__done-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Once any queue has work, the empty ones fold into this one line under the cards (ticket 0104) */
.today-queues__clear {
  padding: 0.45rem 0.9rem;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 0.78rem;
  line-height: 1.6;
}

/* A row's text is truncated inside its row, never wider than the screen: a flex child needs min-width 0 for its
   ellipsis to work (the latest jobs on Home ran to 477 px on a 390 px phone, ticket 0104) */
.summary-main {
  min-width: 0;
}

.summary-main .text-truncate {
  display: block;
  max-width: 100%;
}

/* A phone 390 px wide: the top bar's icons ended at 482 px, the clock and the avatar off the screen (ticket 0104) */
@media (max-width: 419.98px) {
  .navbar-top .navbar-brand img {
    width: 120px;
  }

  .navbar-top .navbar-brand,
  .navbar-top .navbar-toggler {
    margin-right: 0.25rem !important;
  }

  .navbar-top .navbar-nav-icons > .nav-item {
    padding-left: 0.15rem !important;
    padding-right: 0.15rem !important;
  }

  .navbar-top .navbar-nav-icons .avatar-xl {
    width: 2rem;
    height: 2rem;
  }
}

/* Customer journey (customer / enquiry page) */
.customer-journey {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem;
  color: var(--text);
}

.customer-journey .lifecycle-tracker__label {
  font-size: 0.72rem;
}

.customer-journey__next {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px dashed rgba(15, 40, 80, 0.12);
}

.customer-journey__hint {
  font-size: 0.85rem;
  color: #2f3e55;
}

/* Sidebar workspace hint */
.nav-workspace-hint {
  display: block;
  margin: 0 0.5rem;
  padding: 0.6rem 0.75rem;
  border-radius: 0.6rem;
  background: var(--frame-hover);
  color: var(--on-frame);
  text-decoration: none;
  font-size: 0.72rem;
  line-height: 1.35;
}

.nav-workspace-hint:hover {
  background: var(--frame-active);
  color: var(--on-frame);
}

@media (max-width: 1199px) {
  .nav-workspace-hint,
  .nav-workspace-hint:hover {
    background: var(--frame-solid-active);
    color: var(--on-frame-solid);
  }
}

.nav-workspace-hint__label {
  display: block;
  font-weight: 700;
  margin-bottom: 0.15rem;
}

.navbar-vertical-collapsed .nav-workspace-hint__text {
  display: none;
}

/* ==========================================================================
   20. Design System Primitives
   --------------------------------------------------------------------------
   Styles for the shared Blade components in resources/views/components/general.
   Anything here is used by more than one screen; if a rule is only true of one
   screen it belongs in that screen, not in the system.

   Cards: one solid white card (section 6 / 10 above). card-glass, card-clear and card-solid are aliases of it.
   ========================================================================== */

/* Page header ------------------------------------------------------------- */

.page-header__back {
  display: inline-block;
  margin-bottom: 0.15rem;
  font-size: var(--fs-12);
  font-weight: 600;
  color: var(--on-canvas-muted);
  text-decoration: none;
}

.page-header__back:hover {
  color: var(--on-canvas);
}

.page-header__title {
  color: var(--on-canvas);
}

.page-header__subtitle {
  font-weight: 400;
}

.page-header__actions {
  display: flex;
  flex-wrap: wrap;
  max-width: 100%; /* col-auto never shrinks: at phone width the buttons ran off the side instead of wrapping */
  align-items: center;
  justify-content: flex-end;
  gap: 0.35rem;
}

/* A form-select is display:block in Bootstrap, so it would take the whole row
   in a header that mixes a filter with buttons. */
.page-header__actions .form-select,
.page-header__actions .form-control {
  width: auto;
}

.page-header__actions form {
  margin: 0;
}

/* Panel ------------------------------------------------------------------- */

.panel-header--subtle {
  font-weight: 600;
  color: var(--text);
  border-bottom: 1px solid var(--border);
}

/* The kind of record a panel holds (x-general.panel entity=): its colour and white bold text (tokens.css
   --entity-*, the same colours as the .summary-{entity} rows and cards) */
.panel-header--entity {
  background-color: var(--panel-entity) !important;
  color: #fff;
  font-weight: 700;
}
.panel-header--customer { --panel-entity: var(--entity-customer); }
.panel-header--proposal { --panel-entity: var(--entity-proposal); }
.panel-header--task { --panel-entity: var(--entity-task); }
.panel-header--project { --panel-entity: var(--entity-project); }
.panel-header--location { --panel-entity: var(--entity-location); }
.panel-header--product { --panel-entity: var(--entity-product); }
.panel-header--survey { --panel-entity: var(--entity-survey); }

/* A button in a coloured header is a wash of white with white text, so it reads on every colour */
.panel-header--entity .btn:not(.btn-primary):not(.btn-success),
.card-header:is(.bg-primary, .bg-secondary, .bg-success, .bg-info, .bg-warning, .bg-danger, .bg-dark) .btn:not(.btn-primary):not(.btn-success) {
  background-color: rgba(255, 255, 255, 0.18);
  border-color: transparent;
  color: #fff;
}

.panel-header__toggle {
  text-decoration: none;
  line-height: 1;
}

.panel-header__toggle i {
  transition: transform 0.2s ease;
}

.panel-header__toggle[aria-expanded="false"] i {
  transform: rotate(-90deg);
}

/* Filter chips ------------------------------------------------------------ */

.chip-bar {
  margin-bottom: 0;
}

.quick-filter-btn {
  border-radius: 999px;
  font-weight: 600;
}

.quick-filter-btn .badge {
  margin-left: 0.2rem;
  font-weight: 700;
}

/* Empty states ------------------------------------------------------------ */

.empty-state__body {
  max-width: 34rem;
  margin-left: auto;
  margin-right: auto;
}

.empty-state-plain .card-body {
  padding-left: 0;
  padding-right: 0;
}

/* A figure in a small card (a job's revenue, cost, profit and margin): one line, at the card's size (1.5rem) unless
   it is too long for the card's width, then smaller. --N is its length in characters (7 to 14), set by the view;
   a digit is about 0.62em wide in bold. Narrower than 7rem, it wraps rather than run out of the card */
.figure-card {
  container-type: inline-size;
}

.figure-fit {
  font-size: min(1.5rem, 15cqi) !important;
  line-height: 1.2;
  white-space: nowrap;
}

.figure-fit--7 { font-size: min(1.5rem, 23.0cqi) !important; }
.figure-fit--8 { font-size: min(1.5rem, 20.2cqi) !important; }
.figure-fit--9 { font-size: min(1.5rem, 17.9cqi) !important; }
.figure-fit--10 { font-size: min(1.5rem, 16.1cqi) !important; }
.figure-fit--11 { font-size: min(1.5rem, 14.7cqi) !important; }
.figure-fit--12 { font-size: min(1.5rem, 13.4cqi) !important; }
.figure-fit--13 { font-size: min(1.5rem, 12.4cqi) !important; }
.figure-fit--14 { font-size: min(1.5rem, 11.5cqi) !important; }

@container (max-width: 7rem) {
  .figure-fit {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* Stat tiles -------------------------------------------------------------- */

a.stat-tile {
  color: inherit;
  transition: border-color 0.15s ease;
}

a.stat-tile:hover {
  border-color: var(--brand);
}

.stat-tile__value {
  font-weight: 700;
}

/* Pagination -------------------------------------------------------------- */

.pagination-bar .pagination {
  margin-bottom: 0;
}

.pagination-bar .text-mid {
  color: var(--on-canvas-muted) !important;
}

.card .pagination-bar .text-mid {
  color: var(--text-muted) !important;
}

.card .pagination-bar .text-mid,
/* Section headings -------------------------------------------------------- */

.section-heading {
  margin-top: 1.25rem;
}

.section-heading:first-child {
  margin-top: 0;
}

/* Pill buttons - quick actions on the home page, quick filters on lists */

.quick-action-btn {
  border-radius: 999px;
  font-weight: 600;
}

/* Card header defaults ------------------------------------------------------
   A .card-header with no classes gets Bootstrap's grey bar, which sits wrong
   on a frosted card. 47 headers had none and 100 said bg-transparent, so the
   same panel looked like two different components depending on who wrote it.
   Inside the app's own card surfaces, transparent is the default; a screen
   that wants a solid bar still says bg-primary and wins on specificity. */

.card > .card-header:not([class*="bg-"]) {
  background-color: var(--surface);
  border-bottom-color: var(--border);
}

/* Headings inside a card header drift between h5 and h6 across screens; they
   are the same thing, so they read the same size. Scoped to the app's own card
   surfaces: the system admin panel is a separate design family and its plain
   .card headers are left as they are. */
.card-glass > .card-header > h5,
.card-glass > .card-header > h6,
.card-clear > .card-header > h5,
.card-clear > .card-header > h6,
.card-solid > .card-header > h5,
.card-solid > .card-header > h6 {
  font-size: 0.9rem;
  font-weight: 700;
  margin-bottom: 0;
}

/* ==========================================================================
 * Settings page - a long settings form made navigable
 * (docs/CompanyProfileUXAudit.md). A sticky section menu, one panel per
 * section, and a save bar that is always within reach.
 *
 * Usage: .settings-page > (.settings-nav | .settings-section*) + .settings-savebar
 * ========================================================================== */
.settings-page {
  padding-bottom: 5rem; /* room for the save bar */
}

.settings-section {
  scroll-margin-top: 5.5rem; /* clear the app's top bar when jumped to */
  margin-bottom: 1.5rem;
  padding: 0; /* the theme pads every <section> as if it were a landing-page band */
}

.settings-section .card-header h5,
.settings-section .card-header h6 {
  font-size: 1.05rem;
}

/* Where this section's contents end up, in the panel header */
.settings-section__where {
  font-size: 0.8rem;
  opacity: 0.75;
}

/* A heading inside a settings section: sentence case at reading size, never a small all-caps label (D90). It is an
   <h3> (the page title is the h2), so the theme's heading face, line height and spacing are reset to the body's */
.settings-subheading {
  font-family: inherit;
  font-size: var(--fs-16);
  font-weight: 600;
  line-height: inherit;
  letter-spacing: normal;
  color: var(--text);
  margin: 0.5rem 0 0.75rem;
}

.settings-subheading:not(:first-child) {
  margin-top: 0.75rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(11, 23, 39, 0.1);
}

/* Section menu */
.settings-nav {
  position: sticky;
  top: 5.5rem;
  padding: 0.5rem;
  gap: 2px;
}

.settings-nav__link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.75rem;
  border-radius: var(--radius-sm);
  color: inherit;
  text-decoration: none;
  font-size: 0.9rem;
  opacity: 0.8;
  transition: background-color 0.15s ease, opacity 0.15s ease;
}

.settings-nav__link:hover {
  background-color: var(--surface-page);
  color: var(--text);
  opacity: 1;
}

.settings-nav__link.is-active {
  background-color: var(--chip-info-bg);
  color: var(--chip-info);
  font-weight: 600;
  opacity: 1;
}

@media (max-width: 991.98px) {
  .settings-nav {
    position: static;
    flex-direction: row;
    overflow-x: auto;
    white-space: nowrap;
  }

  .settings-nav__link {
    border-left: 0;
    border-bottom: 3px solid transparent;
  }

  .settings-nav__link.is-active {
    border-bottom-color: var(--brand);
  }
}

/* An aside inside a section: context, not a control */
/* A flex row: an icon, then ONE element holding the words. Loose text beside a link, form or <strong> becomes a
   column of its own and squeezes to a word per line at phone width (ticket 0093). */
.settings-note {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  background-color: var(--surface-sunken);
  border: 1px solid var(--border);
  font-size: 0.85rem;
}

.settings-note > i {
  margin-top: 0.2rem;
  opacity: 0.7;
}

.settings-note > :not(i) {
  min-width: 0;
}

/* A link out to a related settings screen */
.settings-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  height: 100%;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--surface-sunken);
  color: inherit;
  text-decoration: none;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.settings-link:hover {
  background-color: var(--surface);
  border-color: var(--brand);
  color: inherit;
}

.settings-link small {
  display: block;
  opacity: 0.7;
}

/* Logo on a white tile: what it will look like on paper */
.settings-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 130px;
  padding: 1rem;
  border-radius: 0.5rem;
  background-color: #fff;
  color: #9da9bb;
}

.settings-logo img {
  max-width: 100%;
  max-height: 100px;
}

/* Live preview of a computed value */
.settings-preview {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1rem;
  border-radius: 0.5rem;
  border: 1px dashed var(--border-control);
  background-color: var(--surface-sunken);
  text-align: center;
}

.settings-preview__label {
  font-size: 0.8rem;
  opacity: 0.7;
}

.settings-preview__value {
  font-size: 1.35rem;
  font-family: var(--falcon-font-monospace, monospace);
  letter-spacing: 0.02em;
}

/* Pick-one cards: the option and its explanation are the same thing */
.settings-choice {
  display: flex;
  gap: 0.75rem;
  height: 100%;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border);
  background-color: var(--surface-sunken);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.settings-choice:hover {
  background-color: var(--surface);
}

.settings-choice:has(input:checked) {
  border-color: var(--brand);
  background-color: var(--chip-info-bg);
}

.settings-choice input {
  margin-top: 0.3rem;
  accent-color: var(--brand);
}

.settings-choice__title {
  display: block;
  font-weight: 600;
}

.settings-choice__text {
  display: block;
  font-size: 0.85rem;
  opacity: 0.75;
}

/* Save bar */
.settings-savebar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1020;
  padding: 0.6rem 1rem;
  background-color: var(--text);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: var(--elev-2);
  color: #fff;
}

.settings-savebar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  max-width: 1320px;
  margin: 0 auto;
  padding-right: 4rem; /* the help widget lives in the bottom-right corner */
}

.settings-savebar__status {
  font-size: 0.9rem;
}

.settings-savebar__status i {
  font-size: 0.55rem;
  vertical-align: middle;
  color: #9da9bb;
}

.settings-savebar[data-dirty="true"] {
  border-top-color: #f5803e;
}

.settings-savebar[data-dirty="true"] .settings-savebar__status i {
  color: #f5803e;
}

.settings-savebar[data-dirty="false"] [data-when="dirty"],
.settings-savebar[data-dirty="true"] [data-when="clean"] {
  display: none;
}

/* A phone: one compact row. The send screen's bar was 128px tall at 390px, "Send the quote" broken over three lines
   and "Not yet" over two. The buttons keep one line and a 44px target; the words beside them get two small lines
   at most, and an aside (.settings-savebar__aside) is left out. */
@media (max-width: 575.98px) {
  .settings-savebar {
    padding: 0.5rem 0.75rem;
  }

  .settings-savebar__inner {
    gap: 0.5rem;
    padding-right: 0;
  }

  .settings-savebar__status {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.8rem;
    line-height: 1.25;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .settings-savebar__aside {
    display: none;
  }

  .settings-savebar__inner > :last-child {
    flex: 0 0 auto;
  }

  .settings-savebar .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding-left: 0.75rem;
    padding-right: 0.75rem;
    white-space: nowrap;
  }
}

/* ==========================================================================
 * Brands - a list, then a workbench per brand (docs/BrandsUXAudit.md):
 * the brand's settings on the left, a live preview that follows on the right.
 *
 * Usage: .settings-page.brand-workbench > .brand-workbench__form + .brand-workbench__preview
 * ========================================================================== */
.settings-nav--row {
  color: #344050; /* outside a panel, so nothing else sets it */
  flex-direction: row;
  flex-wrap: wrap;
  top: 4.5rem;
  z-index: 5;
  margin-bottom: 1rem;
  border-radius: 0.6rem;
}

.settings-nav--row .settings-nav__link {
  border-left: 0;
  border-bottom: 3px solid transparent;
  padding: 0.4rem 0.7rem;
  font-size: 0.85rem;
}

.settings-nav--row .settings-nav__link.is-active {
  border-bottom-color: var(--brand);
}

.brand-workbench {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: 1.5rem;
  align-items: start;
}

.brand-workbench .settings-section {
  scroll-margin-top: 9rem; /* the top bar and the section menu */
}

.brand-workbench__preview {
  position: sticky;
  top: 4.5rem;
}

.brand-preview {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 9.5rem);
  min-height: 420px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background-color: var(--surface);
  color: var(--text);
  overflow: hidden;
}

.brand-preview__bar,
.brand-preview__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.6rem 0.75rem;
}

.brand-preview__foot {
  font-size: 0.8rem;
  opacity: 0.75;
}

.brand-preview__stage {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background-color: #e5e7eb;
}

.brand-preview__stage iframe {
  display: block;
  border: 0;
  background-color: #fff;
  transform-origin: 0 0;
}

@media (max-width: 1199.98px) {
  .brand-workbench {
    grid-template-columns: minmax(0, 1fr);
  }

  .brand-workbench__preview {
    position: static;
    order: -1;
  }

  .brand-preview {
    height: 60vh;
  }
}

/* Colour: picker, hex and a row of starting points */
.brand-colour {
  display: flex;
  gap: 0.5rem;
}

.brand-colour__picker {
  flex: 0 0 2.6rem;
  height: calc(1.5em + 0.75rem + 2px);
  padding: 2px;
  border: 1px solid rgba(11, 23, 39, 0.2);
  border-radius: 0.375rem;
  background-color: #fff;
  cursor: pointer;
}

.brand-swatches {
  display: flex;
  gap: 0.35rem;
  margin-top: 0.5rem;
}

.brand-swatches button {
  width: 1.4rem;
  height: 1.4rem;
  border: 2px solid rgba(255, 255, 255, 0.9);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(11, 23, 39, 0.2);
  cursor: pointer;
}

/* A thumbnail of where the logo sits in the document header */
.brand-layout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  width: 100%;
  min-width: 6.5rem;
  height: 2rem;
  margin-bottom: 0.35rem;
  padding: 0.3rem;
  border-bottom: 2px solid rgba(11, 23, 39, 0.35);
  background-color: #fff;
  border-radius: 0.25rem 0.25rem 0 0;
}

.brand-layout i {
  width: 2rem;
  height: 0.9rem;
  border-radius: 2px;
  background-color: rgba(11, 23, 39, 0.55);
}

.brand-layout b {
  width: 1.4rem;
  height: 0.35rem;
  border-radius: 2px;
  background-color: rgba(11, 23, 39, 0.25);
}

.brand-layout--right {
  flex-direction: row-reverse;
}

.brand-layout--centre {
  flex-direction: column;
  justify-content: center;
  gap: 0.2rem;
}

.brand-layout--centre i {
  height: 0.7rem;
}

/* The brands list: each row is the way in */
.brand-list {
  display: grid;
  gap: 0.75rem;
}

.brand-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 1.1rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background-color: var(--surface);
  color: var(--text); /* a bare link on the canvas inherits white; this row is a white surface */
  text-decoration: none;
  transition: border-color 0.15s ease;
}

.brand-row:hover {
  color: var(--text);
  border-color: var(--brand);
}

.brand-row__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 7.5rem;
  height: 3.5rem;
  padding: 0.4rem;
  border-radius: 0.4rem;
  background-color: #fff;
}

.brand-row__logo img {
  max-width: 100%;
  max-height: 100%;
}

.brand-row__initials {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.7rem;
  height: 2.7rem;
  border-radius: 50%;
  font-weight: 700;
  font-size: 0.9rem;
  overflow: hidden;
}

.brand-list + .settings-note {
  color: #344050;
  background-color: rgba(255, 255, 255, 0.8);
}

.brand-row__main {
  flex: 1;
  min-width: 0;
}

.brand-row__name {
  display: block;
  font-size: 1.05rem;
  font-weight: 600;
}

.brand-row__meta {
  display: block;
  font-size: 0.85rem;
  opacity: 0.75;
}

.brand-row__swatches {
  display: flex;
}

.brand-row__swatches span {
  width: 1.5rem;
  height: 1.5rem;
  margin-left: -0.4rem;
  border: 2px solid #fff;
  border-radius: 50%;
}

.brand-row__go {
  font-size: 0.85rem;
  font-weight: 600;
  white-space: nowrap;
}

.brand-empty {
  padding: 2.5rem 1rem;
  text-align: center;
}

.brand-empty__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 4rem;
  height: 4rem;
  margin-bottom: 1rem;
  border-radius: 50%;
  background-color: rgba(0, 210, 122, 0.18);
  font-size: 1.6rem;
}

/* ==========================================================================
 * Quotes: the journey card on a quote, the send screen, the history list
 * (docs/QuoteToAcceptanceUXAudit.md). The journey card reuses .customer-journey;
 * the send screen reuses .brand-workbench and .brand-preview.
 * ========================================================================== */
.quote-journey__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.quote-journey__actions .btn.w-100 {
  width: auto !important; /* the acceptance button is full-width in a sidebar, not here */
}

.quote-checks {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0.6rem 0.8rem;
  border-radius: 0.5rem;
  background-color: #fff8e6;
  color: #5c4a12;
  font-size: 0.85rem;
}

.quote-checks li + li {
  margin-top: 0.3rem;
}

.quote-checks li i {
  width: 1.1rem;
  color: #d39e00;
}

.quote-checks li.is-blocking i {
  color: #dc3545;
}

.quote-checks--panel {
  margin-top: 0;
}

.quote-history {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.85rem;
}

.quote-history li {
  display: flex;
  gap: 0.75rem;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--border);
}

.quote-history li:last-child {
  border-bottom: 0;
}

.quote-history__when {
  flex: 0 0 4.2rem;
  opacity: 0.7;
  white-space: nowrap;
}

.quote-send__effects {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.9rem;
}

.quote-send__effects li {
  display: flex;
  gap: 0.65rem;
  padding: 0.3rem 0;
}

.quote-send__effects li i {
  flex: 0 0 1.1rem;
  margin-top: 0.2rem;
  opacity: 0.75;
}

.quote-send .brand-workbench__form .card {
  margin-bottom: 1rem;
}

.quote-line--off td {
  opacity: 0.55;
}

.quote-line--off td:first-child {
  opacity: 1;
}

.quote-message {
  margin: 0 1.25rem 0.5rem 0;
  padding: 0.5rem 0.7rem;
  border-radius: 10px 10px 10px 3px;
  background-color: var(--surface-page);
  font-size: 0.85rem;
  overflow-wrap: anywhere;
}

.quote-message.is-ours {
  margin: 0 0 0.5rem 1.25rem;
  border-radius: 10px 10px 3px 10px;
  background-color: rgba(46, 204, 113, 0.22);
}

.quote-message__who {
  display: block;
  font-size: 0.7rem;
  opacity: 0.75;
}

/* ==========================================================================
 * Job guide: every step of a job, what is set and what is not (docs/JobGuideUXAudit.md)
 * Usage: .job-guide > .job-guide__steps > details.job-guide__step.is-{done|current|gap|todo|off}
 * Sits inside an x-general.panel on the job's Overview; the next action is on the bar under the header (ticket 0112).
 * ========================================================================== */
.job-guide__step {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--surface);
}

.job-guide__step + .job-guide__step { margin-top: 0.4rem; }
.job-guide__step.is-current { border-color: var(--action); background-color: var(--action-tint); }
.job-guide__step.is-gap { border-color: var(--chip-wait-bg); }

.job-guide__step > summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.85rem;
  cursor: pointer;
  list-style: none;
  color: var(--text);
}

.job-guide__step > summary::-webkit-details-marker { display: none; }

.job-guide__dot {
  flex: 0 0 1.9rem;
  height: 1.9rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: var(--fs-12);
  background-color: var(--chip-neutral-bg);
  color: var(--chip-neutral);
}

.is-done > summary .job-guide__dot { background-color: var(--chip-done-bg); color: var(--chip-done); }
.is-current > summary .job-guide__dot { background-color: var(--action); color: var(--on-action); }
.is-gap > summary .job-guide__dot { background-color: var(--chip-wait-bg); color: var(--chip-wait); }
.job-guide__step.is-off { border-style: dashed; background-color: var(--surface-sunken); }
.is-off > summary .job-guide__label { color: var(--text-muted); }

.job-guide__label { flex: 0 0 auto; min-width: 8.5rem; font-weight: 600; }
.job-guide__summary { flex: 1 1 auto; min-width: 0; font-size: var(--fs-14); color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-guide__count { font-size: var(--fs-12); font-weight: 600; padding: 0.1rem var(--space-2); border-radius: var(--radius-pill); background-color: var(--chip-wait-bg); color: var(--chip-wait); white-space: nowrap; }
.job-guide__chevron { font-size: var(--fs-12); color: var(--text-muted); transition: transform 0.15s; }
.job-guide__step[open] .job-guide__chevron { transform: rotate(180deg); }

.job-guide__body { padding: 0.25rem 0.85rem 0.75rem 3.5rem; }

.job-guide__facts { list-style: none; margin: 0; padding: 0; font-size: var(--fs-14); color: var(--text); }
.job-guide__facts li { display: flex; align-items: baseline; gap: 0.5rem; padding: 0.3rem 0; border-top: 1px dashed var(--border); }
.job-guide__facts li:first-child { border-top: 0; }
.job-guide__facts li > i { flex: 0 0 1rem; font-size: 0.8rem; }
.job-guide__facts .is-set > i { color: var(--chip-done); }
.job-guide__facts .is-open > i { color: var(--chip-wait); }
.job-guide__facts .is-optional > i { color: var(--border-control); }
.job-guide__facts .is-optional { color: var(--text-muted); }
.job-guide__fact { flex: 1 1 auto; }
.job-guide__fix { flex: 0 0 auto; font-weight: 600; white-space: nowrap; }

.job-guide__moves { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: 0.5rem; }

.stage-warnings {
  margin: 0.75rem 0;
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  background-color: var(--chip-wait-bg);
  border: 1px solid var(--chip-wait-bg);
  color: var(--chip-wait);
  font-size: var(--fs-14);
}

.stage-warnings ul { margin: 0.4rem 0 0.6rem; padding-left: 1.1rem; }
.stage-warnings small { display: block; margin-top: 0.5rem; opacity: 0.8; }

.lifecycle-tracker__step { position: relative; }
.lifecycle-tracker__link { position: absolute; inset: 0; z-index: 2; }

@media (max-width: 767.98px) {
  .job-guide__summary { display: none; }
  .job-guide__body { padding-left: 0.85rem; }
}

/* Livewire's own paginator prints "Showing 1 to 25 of 98 results" under <x-general.pagination>, which has already
   said "Showing 1-25 of 98 customers". Say it once, with the right noun. */
.pagination-bar nav p.small.text-muted {
  display: none;
}


/* Sales board: columns side by side on a wide screen; on a phone, the one column picked above the board */
.kanban-columns { min-width: max-content; }
.kanban-column { width: 280px; flex-shrink: 0; }
@media (max-width: 767.98px) {
    .kanban-columns { min-width: 0; }
    .kanban-column { display: none; width: 100%; }
    .kanban-column.is-phone-stage { display: block; }
}


/* ── Calendar: the top bar and the month grid's own header ────────────────────────────────────────
   Two sticky things were both pinned to top: 0: the app's top bar (.navbar-top) and FullCalendar's day-name row,
   which ghosted through each other. The top bar is solid now (section 1: it paints the canvas, scrolled or not; the
   admin panel's bar takes the body colour once scrolled), and the grid's header stops below it rather than sliding
   under it. */
.fc .fc-scrollgrid-section-header.fc-scrollgrid-section-sticky > * {
  top: var(--installa-top-nav-height, 4.3125rem);
  z-index: 2; /* the top bar is 1020: the day names pass under it, never over */
}

/* The same for the week list, which is the view a phone opens on */
.fc .fc-list-sticky .fc-list-day > * {
  top: var(--installa-top-nav-height, 4.3125rem);
  z-index: 2;
}


/* Designer: the Solar Analysis strip carries two annual figures worked out two different ways, so each
   says under itself where its number came from (the tooltip says it at length). */
.stats-strip .stat-note {
  font-size: 0.65rem;
  line-height: 1.2;
  text-transform: none;
  letter-spacing: 0;
  /* A long note (a market with no figure for some faces) wraps under its figure rather than pushing the strip's
     other figures onto a ragged second line */
  white-space: normal;
  max-width: 22rem;
}


/* ── Pick one of a few: tiles and chips ───────────────────────────────────────────────────────────
   Bootstrap's .btn-check + .btn-outline-* only changes colour when it is checked, and the screens
   that used it wrote their own overrides in a @push('styles') block. Those blocks reached for
   var(--installa-secondary), which this theme does not define (it has --installa-secondary-rgb and
   --installa-secondary-color, not that): the background resolved to nothing and a selected tile was
   white text on a white card. These are the same controls, written once, in tokens that exist.
   Used by: start a job (screens/projects/startproject). */

.choice-tile,
.choice-chip {
  display: flex;
  cursor: pointer;
  border: 2px solid rgba(36, 72, 140, 0.18);
  background: #fff;
  color: #1f2a3d;
  transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.choice-tile {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
  height: 100%;
  min-height: 5.25rem;
  padding: 0.85rem 0.6rem;
  border-radius: 12px;
  text-align: center;
  font-weight: 600;
  line-height: 1.25;
}

.choice-tile i {
  color: var(--installa-primary, #279ef9);
}

.choice-chip {
  align-items: center;
  padding: 0.35rem 0.8rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
}

.choice-tile--wide {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 0.75rem;
  padding: 0.5rem;
  text-align: left;
  font-weight: 500;
}

.choice-tile:hover,
.choice-chip:hover {
  border-color: var(--installa-primary, #279ef9);
  background: var(--installa-primary-bg-subtle, #d8eefe);
}

/* Checked: a filled tile in the brand blue, with white text that has 4.5:1 against it, and the
   focus ring drawn on the label because the input itself is visually hidden. */
.btn-check:checked + .choice-tile,
.btn-check:checked + .choice-chip {
  border-color: var(--installa-primary, #279ef9);
  background: var(--installa-primary-text-emphasis, #1d77bb);
  color: #fff;
  box-shadow: 0 0 0 3px rgba(var(--installa-primary-rgb, 39, 158, 249), 0.25);
}

.btn-check:checked + .choice-tile i {
  color: #fff;
}

.btn-check:focus-visible + .choice-tile,
.btn-check:focus-visible + .choice-chip {
  outline: 3px solid var(--installa-primary, #279ef9);
  outline-offset: 2px;
}

.btn-check:disabled + .choice-chip {
  opacity: 0.45;
  cursor: default;
}

/* The map thumbnail and the address lines beside it, on a tile or on its own */
.address-card__map {
  width: 72px;
  height: 72px;
  flex: 0 0 auto;
  border-radius: 8px;
  object-fit: cover;
  background: rgba(36, 72, 140, 0.08);
}

.address-card__lines {
  line-height: 1.35;
  font-size: 0.875rem;
}

.address-card--only {
  padding: 0.75rem;
  border: 2px solid var(--installa-success-border-subtle, #99edca);
  border-radius: 12px;
  background: var(--installa-success-bg-subtle, #d9f8eb);
  color: #1f2a3d;
}

/* Survey photo slots (ticket 0050): a row of thumbnails, each with a remove button, beside "Add photo" */
.survey-photo-slot__thumb { position: relative; width: 64px; height: 64px; }
.survey-photo-slot__thumb img,
.survey-photo-slot__file { width: 64px; height: 64px; object-fit: cover; border-radius: .375rem; display: flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, .15); }
.survey-photo-slot__remove { position: absolute; top: -6px; right: -6px; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 50%; background: #dc3545; color: #fff; font-size: .7rem; line-height: 22px; }


/* ── Banners in the content column (ticket 0089 P1) ───────────────────────────────────────────────
   Verify-email, billing, announcement and impersonation banners sit under the top bar, inside .content,
   so neither the fixed sidebar's logo (desk) nor the top bar's (phone) is ever covered. The banners are
   full-bleed strips; .content pads its sides, so they keep a small gap and rounded corners instead. A
   sticky banner (impersonation) stops below the top bar rather than sliding under it. */
.app-banners > .alert {
  border-radius: 0.375rem !important;
  margin-bottom: 0.5rem !important;
}

.app-banners > .sticky-top {
  top: var(--installa-top-nav-height, 4.3125rem);
  z-index: 1015 !important;
}

/* ==========================================================================
   The app's own "are you sure?" (partials/confirm-dialog, resources/js/theme/confirm.js, ticket 0090)
   ========================================================================== */
/* Above any modal it was asked from (Bootstrap modals sit at 1055, their backdrops at 1050). */
.modal.installa-confirm { z-index: 1090; }
.modal-backdrop.installa-confirm-backdrop { z-index: 1085; }
.installa-confirm .modal-content { border-radius: 0.75rem; }
.installa-confirm .modal-title { font-size: 1.05rem; line-height: 1.4; overflow-wrap: anywhere; }
/* Messages may carry their own line breaks (the commissioning list). */
.installa-confirm .modal-body { white-space: pre-line; overflow-wrap: anywhere; }
.installa-confirm .modal-footer { gap: 0.5rem; }
.installa-confirm .modal-footer > .btn { margin: 0; }
@media (max-width: 575.98px) {
  /* A phone: the two buttons share the width, confirm still on the right. */
  .installa-confirm .modal-footer > .btn { flex: 1 1 0; }
}

/* ==========================================================================
   One look across the app (ticket 0093)
   ========================================================================== */
/* A card with an open menu sits above its neighbours, so a quote line's "…" menu never goes under the card beside it. */
.card:has(.dropdown-menu.show) {
  z-index: 5;
}

/* Toasts live bottom-right (partials/confirm-dialog), clear of every page heading. On a screen with a save bar
   they sit just above it, so a confirmation never covers the Save button. */
body:has(.settings-savebar) #globalToastArea {
  bottom: 3.75rem !important;
}

/* A row's name (the <strong> a list leads with) reads in full body colour, not the table's grey, and keeps it on
   a hovered or greyed (revoked, inactive) row: the API keys list showed its key names pale on a pale row. */
.table:not(.table-dark) > tbody > tr > td strong:not(a strong) {
  color: var(--text);
}

/* ==========================================================================
   Who did it, on a history line (ticket 0092, x-general.actor)
   ========================================================================== */
/* The customer acting in their portal is marked out, so it never reads as the installer's own line. Colour comes from
   the container (white on glass, dark on a solid card); the tint and border carry the difference. */
.actor--customer {
  display: inline-block;
  padding: 0 .45em;
  border-radius: 999px;
  border: 1px solid rgba(13, 202, 240, .55);
  background: rgba(13, 202, 240, .14);
  font-weight: 600;
  white-space: nowrap;
}
.actor--system {
  font-style: italic;
  opacity: .85;
}

/* Find a roof (ticket 0102): Home's address box. Google's suggestion list is appended to <body>, so it must sit above
   cards and the sticky top bar. */
.find-roof--compact { min-width: min(20rem, 100%); }
.find-roof--compact .form-control { min-width: 10rem; }
body > .pac-container { z-index: 2000; }

/* ==========================================================================
   The record page (ticket 0108): x-general.record-header, x-general.next-step, the tabs and the side column.
   Who, where it stands, the one thing to do. A colour is a tint or an icon here, never a coloured left border.
   ========================================================================== */
.record-header { display: flex; flex-direction: column; gap: var(--space-3); margin-bottom: var(--space-3); }
.record-header__card { padding: var(--space-4); gap: var(--space-3); color: var(--text); }
.record-header__row { display: flex; align-items: flex-start; gap: var(--space-3); min-width: 0; }
.record-header__icon {
  flex: none; display: inline-grid; place-items: center; width: 2.25rem; height: 2.25rem;
  border-radius: var(--radius-pill); background: var(--surface-page); color: var(--text-muted);
}
.record-header__icon--customer { background: var(--entity-customer); color: var(--on-action-2); }
.record-header__icon--project { background: var(--entity-project); color: var(--on-action-2); }
.record-header__icon--proposal { background: var(--entity-proposal); color: var(--on-action-2); }
.record-header__who { flex: 1 1 auto; min-width: 0; }
.record-header__line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-width: 0; }
.record-header__name {
  margin: 0; font-size: var(--fs-20); line-height: var(--lh-tight); font-weight: 700; color: var(--text);
  overflow-wrap: anywhere;
}
.record-header__subtitle { color: var(--text-muted); font-size: var(--fs-14); }
.record-header__ref { color: var(--text-muted); font-size: var(--fs-14); margin-top: var(--space-1); overflow-wrap: anywhere; }
.record-header__tools { flex: none; display: flex; align-items: center; gap: var(--space-2); }
.record-header__brand { width: 2.5rem; height: auto; border-radius: var(--radius-sm); }
.record-header__more { min-width: 15rem; }
.record-header__facts {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3);
  margin: 0; padding-top: var(--space-3); border-top: 1px solid var(--border);
}
.record-header__fact { min-width: 0; }
.record-header__fact dt { font-size: var(--fs-12); font-weight: 400; color: var(--text-muted); }
.record-header__fact dd { margin: 0; font-size: var(--fs-14); font-weight: 600; color: var(--text); overflow-wrap: anywhere; }

.next-step {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-4);
  padding: var(--space-4); background: var(--action-tint); color: var(--text);
}
.next-step__icon {
  display: inline-grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: var(--radius-pill);
  background: var(--action); color: var(--on-action);
}
.next-step__body { min-width: 0; }
.next-step__track { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0 0 var(--space-2); padding: 0; list-style: none; }
.next-step__step {
  padding: 2px var(--space-2); border-radius: var(--radius-sm); font-size: var(--fs-12);
  background: var(--surface); color: var(--text-muted); border: 1px solid var(--border);
}
.next-step__step i { margin-right: var(--space-1); }
.next-step__step.is-done { background: var(--chip-done-bg); color: var(--chip-done); border-color: transparent; }
.next-step__step.is-current { background: var(--chip-wait-bg); color: var(--chip-wait); border-color: transparent; font-weight: 700; }
.next-step__hint { margin: 0; font-size: var(--fs-14); color: var(--text); }
.next-step__missing { margin: var(--space-1) 0 0; font-size: var(--fs-14); display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-2); }
.next-step__missing .btn-link { font-size: inherit; font-weight: inherit; color: var(--link); text-decoration: none; }
.next-step__actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); }
.next-step__step.is-gap { color: var(--chip-wait); border-color: var(--chip-wait-bg); }
.next-step__step.is-gap i { margin-right: var(--space-1); }
/* A step the job's kind of work does not go through (ticket 0084): still listed, struck through and quiet */
.next-step__step.is-off { color: var(--text-muted); border-style: dashed; text-decoration: line-through; }
.next-step--parked { background: var(--surface-sunken); }
.next-step--parked .next-step__icon { background: var(--chip-neutral-bg); color: var(--chip-neutral); }

.record-tabs {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0;
  padding: 0 var(--space-4); gap: var(--space-4); flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
  margin-bottom: var(--space-3);
}
.record-tabs .nav-link {
  padding: var(--space-3) 0; border: 0; color: var(--text-muted); background: transparent; white-space: nowrap;
}
.record-tabs .nav-link.active { color: var(--text); font-weight: 600; background: transparent; box-shadow: inset 0 -2px 0 var(--brand); }
.record-tab-content__lead { color: var(--on-canvas); }
.record-tab-content__lead a { color: inherit; text-decoration: underline; }

/* One row in a side panel or a tab's list: the thing on the left, its state on the right, the whole row a link */
.record-list-row {
  display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-2);
  padding: var(--space-1) 0; border-bottom: 1px solid var(--border); color: var(--text); text-decoration: none;
}
.record-list-row:last-child { border-bottom: 0; }
.record-list-row:hover { color: var(--link); }
.record-more-toggle { color: var(--on-canvas); text-decoration: none; padding: 0 0 var(--space-3); }
.record-more-toggle:hover { color: var(--on-canvas-muted); }

/* The job page (ticket 0112): the stage control and the waiting note sit inside the next-step bar; photos in a grid */
.lifecycle-control .next-step { margin: 0; }
.lifecycle-control__waiting { color: var(--text); }
.job-file-phase { margin-top: var(--space-4); }
.job-file-phase__title { font-size: var(--fs-14); font-weight: 700; margin: 0 0 var(--space-1); color: var(--text); }
.record-thumbs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-1); }
.record-thumbs--wide { grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr)); }
.record-thumbs a { display: block; aspect-ratio: 1; overflow: hidden; border-radius: var(--radius-sm); background: var(--surface-sunken); }
.record-thumbs img { width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 767.98px) {
  .record-header__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .next-step { grid-template-columns: minmax(0, 1fr); }
  .next-step__icon { display: none; }
  .next-step__actions { justify-content: flex-start; }
}

/* ==========================================================================
   Tab panel (ticket 0114, x-general.tab-panel): a record's tabs as its main navigation. A solid band of block tabs in
   the job's colour, fused to one white panel; the open tab is white and runs into the panel with no line between.
   A card placed straight in a tab draws as a section of the panel (a heading and its body), not as a card of its own;
   cards inside those sections stay cards. Colour goes in the band and the section icons, never in a stripe.
   ========================================================================== */
.tab-panel { margin-bottom: var(--space-6); }
.tab-panel__bar {
  display: flex; flex-wrap: nowrap; gap: var(--space-1); margin: 0; padding: var(--space-2) var(--space-2) 0;
  background: var(--tab-band); border-radius: var(--radius) var(--radius) 0 0; list-style: none;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none; overscroll-behavior-x: contain;
}
.tab-panel__bar::-webkit-scrollbar { display: none; }
.tab-panel__bar .nav-item { flex: none; }
.tab-panel__tab.nav-link {
  display: inline-flex; align-items: center; gap: 6px; min-height: 48px; margin: 0;
  padding: var(--space-3) 10px; border: 0; border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: var(--tab-idle); color: var(--on-tab); font-size: 0.9375rem; font-weight: 600; line-height: var(--lh-tight);
  white-space: nowrap;
}
.tab-panel__tab.nav-link:hover,
.tab-panel__tab.nav-link:focus { background: var(--tab-hover); color: var(--on-tab); }
.tab-panel__tab.nav-link:focus-visible { outline: 2px solid var(--on-tab); outline-offset: -4px; box-shadow: none; }
.tab-panel__tab.nav-link.active,
.tab-panel__tab.nav-link.active:hover,
.tab-panel__tab.nav-link.active:focus { background: var(--tab-active); color: var(--on-tab-active); }
.tab-panel__tab.nav-link.active:focus-visible { outline-color: var(--link); }
.tab-panel__tab i { font-size: var(--fs-14); }
.tab-panel__body {
  background: var(--surface); border: 1px solid var(--border); border-top: 0; border-radius: 0 0 var(--radius) var(--radius);
  padding: var(--space-6) var(--space-6) 0;
}
.tab-panel__body > .tab-pane { padding-bottom: var(--space-2); }

/* A card straight in a tab is a section: no frame, a dark heading with its kind's colour in the icon, a hairline under */
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) {
  background: transparent; border: 0; border-radius: 0; box-shadow: none !important; margin-bottom: var(--space-6) !important;
}
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-header {
  margin: 0; padding: 0 0 var(--space-2); min-height: 0; border: 0; border-bottom: 1px solid var(--border);
  border-radius: 0; background: transparent !important; color: var(--text) !important; font-size: var(--fs-16); font-weight: 700;
}
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-header :is(.text-white, h5, h6) { color: var(--text) !important; }
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-header :is(h5, h6) { font-size: inherit; font-weight: 700; margin: 0; }
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-header .panel-header__label i { color: var(--text-muted); margin-right: var(--space-1); }
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .panel-header--entity .panel-header__label i { color: var(--panel-entity); }
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-header .btn:not(.btn-primary):not(.btn-success) {
  background-color: var(--installa-btn-bg); border-color: var(--installa-btn-border-color); color: var(--installa-btn-color);
}
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-header .btn:not([class*="btn-"]) { color: var(--text-muted); }
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-body:not(.p-0),
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > div:not(.card-body):not(.card-header) > .card-body:not(.p-0) {
  padding: var(--space-3) 0 0 !important; background: transparent;
}
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-body.p-0,
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > div:not(.card-body):not(.card-header) > .card-body.p-0 { background: transparent; }
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > .card-footer,
.tab-panel__body .card:not(.tab-panel__body .card .card, .modal .card) > div:not(.card-body):not(.card-header) > .card-footer {
  padding: var(--space-2) 0 0; background: transparent; border-top: 1px solid var(--border);
}

/* Under a wide desk the icons go, so all seven labels still fit beside the side column (a 1280 laptop) */
@media (max-width: 1399.98px) {
  .tab-panel__tab i { display: none; }
}
@media (max-width: 575.98px) {
  .tab-panel__bar { padding: var(--space-1) var(--space-1) 0; }
  .tab-panel__tab.nav-link { padding: var(--space-3); font-size: var(--fs-14); }
  .tab-panel__body { padding: var(--space-4) var(--space-4) 0; }
}
/* A component that brings its own .card-body (the site map) sits flush in a section's body, not inset again */
.tab-panel__body .card-body > .card-body { padding: 0; margin-bottom: var(--space-3); }

/* A new account's first screen (ticket 0116): one welcoming card in the middle of the map, holding the address box.
   Full width less a 16px gutter on a phone. The map stays usable around it. */
.roof-finder {
  position: fixed;
  inset: 0;
  z-index: 1001;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--space-4);
  pointer-events: none;
}
.roof-finder__card {
  pointer-events: auto;
  width: min(36rem, 100%);
  border-radius: var(--radius);
  box-shadow: var(--elev-1);
}
.roof-finder__card .card-body { padding: var(--space-6); }
.roof-finder__title {
  margin: 0 0 var(--space-1);
  font-size: var(--fs-32);
  line-height: var(--lh-tight);
  font-weight: 700;
  color: var(--text);
}
.roof-finder__lead {
  margin: 0 0 var(--space-4);
  font-size: var(--fs-16);
  color: var(--text-muted);
}
.roof-finder .pac-card#pac-card {
  position: static !important;
  margin: 0 0 var(--space-3);
  width: 100%;
  overflow: visible;
}
.roof-finder #pac-container { margin: 0; padding: 0; }
.roof-finder #pac-input {
  width: 100%;
  max-width: 100%;
  height: 3.5rem;
  padding: 0 var(--space-4);
  font-family: var(--font-ui);
  font-size: var(--fs-20);
  font-weight: 400;
  color: var(--text);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-sm);
  box-shadow: none;
}
.roof-finder #pac-input:focus { border-color: var(--action); outline: 2px solid var(--action); outline-offset: 0; }
.roof-finder__home { font-size: var(--fs-14); color: var(--text-muted); }
.roof-finder__home:hover { color: var(--link-hover); }
@media (max-width: 576px) {
  .roof-finder__card .card-body { padding: var(--space-4); }
  .roof-finder__title { font-size: var(--fs-24); }
}

/* The map's address box on a phone (ticket 0116): clear of the round logo button in the top-left corner, which sat
   over the first words of the box on a new account's first screen */
@media (max-width: 576px) {
  #pickmap .pac-card,
  .pac-card#pac-card { margin-left: 3.25rem; }
  #pac-input { max-width: calc(100vw - 4.75rem); }
}

/* Google's address suggestions open over the map's cards, the first-look card included, on a solid surface (ticket 0116) */
.pac-container { z-index: 1100; background-color: var(--surface); }
/* The picked roof's one line about look-ups (ticket 0116) */
.roof-lookups-line { color: var(--text-muted); }

/* ==========================================================================
   Try it before signing up (ticket 0118): the public address page (try/start, try/demo) and the read-only preview of
   the designer (screens/showsite with $preview). One white card on the canvas; the preview hides every tool.
   ========================================================================== */
.try-card__title {
  margin: 0 0 var(--space-2);
  font-size: var(--fs-24);
  font-weight: 700;
  line-height: 1.25;
  color: var(--text);
}
.try-look__row {
  display: flex;
  gap: var(--space-2);
  align-items: stretch;
}
.try-look__row .form-control { flex: 1 1 auto; min-width: 0; }
.try-look__row .btn { flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 575.98px) {
  .try-look__row { flex-direction: column; }
  .try-card__title { font-size: var(--fs-20); }
}
body.try-preview #toolbar,
body.try-preview #modeIndicator,
body.try-preview #saveStatus { display: none !important; }
/* Read-only for somebody who may only look at the job (ticket 0193): the roof and its card, no tools, no save status */
body.designer-readonly #toolbar,
body.designer-readonly #modeIndicator,
body.designer-readonly #saveStatus { display: none !important; }
/* The save status when it holds a choice (saved by somebody else since; another tab's draft): the words wrap and the
   buttons sit under them, inside the screen on a phone */
#saveStatus.save-status--choice {
  flex-wrap: wrap;
  justify-content: center;
  max-width: min(36rem, calc(100vw - 32px));
  border-radius: var(--radius);
  cursor: default;
}
#saveStatus.save-status--choice .save-status-text { white-space: normal; text-align: center; }
#saveStatus.save-status--choice .save-status-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: center; }
#saveStatus.save-status--choice .save-status-actions.d-none { display: none !important; }
/* The preview is the roof and its card only: the 3D view takes the whole window (the designer's is 600px, with the
   analysis under it) */
#canvasWrapper.try-preview-canvas #installaverse { height: 100vh; height: 100dvh; }
@media (max-width: 576px) {
  /* No tools on the left in the preview: the card takes the width, under the address and the way back */
  #canvasWrapper.try-preview-canvas .designer-summary { top: 84px; left: 8px; right: 8px; }
}

/* The map's credit for OpenStreetMap's building outlines (ticket 0122, ODbL): small, legible on the aerial picture */
.map-credit {
  margin: 0 0 var(--space-1) var(--space-1);
  padding: 1px var(--space-2);
  background: var(--surface);
  color: var(--text);
  border-radius: var(--radius-sm);
  font: 400 var(--fs-12) / var(--lh) var(--font-ui);
}
.map-credit a { color: var(--link); }
.map-credit--top { margin: calc(var(--space-12) + var(--space-3)) 0 0 var(--space-2); }

/* A settings list that is a table on a wide screen and a stack of cards below md (ticket 0139, quote templates):
   each row is a card, each cell a line with its heading from data-label, and the actions are always on screen. */
@media (max-width: 767.98px) {
  .table-stack-md thead { display: none; }
  .table-stack-md, .table-stack-md tbody, .table-stack-md tr, .table-stack-md td { display: block; width: 100%; }
  .table-stack-md tr {
    margin: var(--space-2);
    width: auto;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
  }
  .table-stack-md td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-1) 0;
    border: 0;
    text-align: right !important;
  }
  .table-stack-md td[data-label]::before {
    content: attr(data-label);
    color: var(--text-muted);
    text-align: left;
    flex: 0 0 auto;
  }
  .table-stack-md td.table-stack-title { display: block; text-align: left !important; font-size: 1.05em; }
  .table-stack-md td.table-stack-actions { justify-content: flex-end; padding-top: var(--space-2); }
}

/* Brands on a phone (ticket 0141): the logo cell gives the name room, and the preview comes after the form */
@media (max-width: 767.98px) {
  .brand-row__logo { flex-basis: 4rem; height: 2.5rem; }
  .brand-workbench__preview { order: 1; }
  .brand-preview { height: 50vh; }
}

/* The email editor (ticket 0141: was a private <style> block on email-templates-edit) */
#editor-visual.ql-container { font-size: var(--fs-14); }
#editor-visual .ql-editor { min-height: 300px; }

/* Certifications: "Update expiry" opens its date in place */
.credential-expiry > summary { list-style: none; }
.credential-expiry > summary::-webkit-details-marker { display: none; }

/* Lists on a phone (ticket 0166) ------------------------------------------------------------------------------------ */
/* A Livewire list's filters fold behind "Filters (n)" below md: the search and the tools stay, the rest open on a tap */
@media (max-width: 767.98px) {
  .live-filter-fields:not(.is-open) > :not(:first-child):not(.live-filter-tools) { display: none !important; }
}
/* The floating bar for ticked rows: it wraps, and below 576px the buttons are icons (their words stay for a screen reader
   and the tooltip), so five actions fit a 390px screen */
.bulk-action-bar { z-index: 1050; flex-wrap: wrap; justify-content: center; max-width: calc(100vw - var(--space-4) * 2); }
@media (max-width: 575.98px) {
  .bulk-action-bar { gap: var(--space-2) !important; padding: var(--space-2) var(--space-3) !important; border-radius: var(--radius) !important; width: calc(100vw - var(--space-4) * 2); }
  .bulk-action-bar .bulk-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .bulk-action-bar .vr { display: none; }
  .bulk-action-bar .btn { min-width: 44px; min-height: 44px; }
}
/* A row's tick box: an 18px box inside a 44px tap target (as 0144) */
.row-select { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; margin: calc(var(--space-2) * -1) var(--space-1) 0 calc(var(--space-2) * -1); cursor: pointer; }
.row-select .form-check-input { width: 18px; height: 18px; margin: 0; cursor: pointer; }
/* Where a job is, under its customer */
.summary-where { max-width: 36rem; }
/* Documents: the table's fixed columns, and the phone's cards */
.documents-col-icon { width: 40px; }
.documents-col-actions { width: 120px; }
.document-card__icon { flex: 0 0 auto; width: 24px; text-align: center; padding-top: 2px; }
.document-card__action { min-height: 44px; display: inline-flex; align-items: center; }
/* A quote row on a phone: the price folds under the name instead of squeezing it */
@media (max-width: 767.98px) {
  .summary-proposal .summary-price { display: none !important; }
}

/* Calendar (ticket 0161): an on-hold install keeps its day, hatched; legend swatches in the calendar's event colours */
.calendar-on-hold { background-image: repeating-linear-gradient(135deg, rgba(255, 255, 255, .4) 0 6px, transparent 6px 12px); }
.calendar-swatch--unassigned { background-color: #6c757d; }
.calendar-swatch--survey { background-color: #17a2b8; }
.calendar-swatch--visit { background-color: #20c997; }
.calendar-swatch--outside { background-color: #6f42c1; }

/* The quote builder's product box (ticket 0169): your products, then the library, in one scrolling list */
.qb-product-picker { max-height: 16rem; overflow-y: auto; }
/* The designer's product picker (ticket 0171): the product's own picture, kept inside its column */
.picker-product-image { max-height: 160px; object-fit: contain; }
/* The products list (ticket 0171): fixed columns as classes, and each row stacked on a phone (name, then the two prices
   at half the width each, the unit inside the box) instead of 33rem of columns scrolling sideways */
.price-list .col-check { width: 2rem; }
.price-list .col-money { width: 9rem; }
.price-list .col-unit { width: 6.5rem; }
.price-list .col-margin { width: 5rem; }
.bulk-percent { width: 7rem; }
.markup-input { max-width: 12rem; }
@media (max-width: 767.98px) {
  .price-list--stack thead { display: none; }
  .price-list--stack tbody tr { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-1); border-bottom: 1px solid var(--border); }
  .price-list--stack tbody td { display: block; border: 0; padding: 0; }
  .price-list--stack tbody td.cell-name { flex: 1 1 0; min-width: 0; order: 1; }
  .price-list--stack tbody td.cell-check { order: 0; }
  .price-list--stack tbody td.cell-open { order: 2; }
  .price-list--stack tbody td.cell-money { order: 3; flex: 1 1 calc(50% - var(--space-2)); min-width: 0; }
  .price-list--stack tbody td.cell-unit { order: 4; }
}

/* ==========================================================================
   A job's task row (ticket 0176)
   On a phone the title has the row to itself, with one line under it (who, when, status) and one menu; from md up the
   assign, due, status and buttons sit beside it. The people to give a task to are one list for the whole task list.
   ========================================================================== */
.task-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
}
.task-row__handle {
  cursor: grab;
  padding-top: 2px;
}
.task-item .drag-handle:hover {
  color: var(--text);
}
.task-row__check {
  flex: 0 0 auto;
}
.task-row__main {
  flex: 1 1 auto;
  min-width: 0; /* lets a long title wrap instead of pushing the row sideways */
}
.task-row__title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
  overflow-wrap: anywhere;
}
.task-row__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
  margin-top: 2px;
}
.task-row__controls {
  flex: 0 0 auto;
  align-items: center;
  gap: var(--space-3);
}
.task-row__assignee {
  min-width: 8.5rem;
  text-align: left;
}
.task-row__due {
  min-width: 4rem;
  text-align: right;
}
.task-row__menu {
  flex: 0 0 auto;
}
.sortable-ghost {
  opacity: 0.4;
  background: var(--surface-sunken);
}

/* Who to give a task to: one panel over the page, at the foot of a phone screen and in the middle of a desk one */
.task-assign {
  position: fixed;
  inset: 0;
  z-index: 1060;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(15, 23, 42, 0.5);
}
.task-assign__panel {
  width: 100%;
  max-width: 24rem;
  max-height: 70vh;
  margin: 0;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.task-assign__list {
  overflow-y: auto;
}
@media (min-width: 768px) {
  .task-assign {
    align-items: center;
  }
  .task-assign__panel {
    border-radius: var(--radius);
  }
}

/* Printing a report (ticket 0182): the figures of the chosen period, without the app's navigation */
@media print {
  .navbar-vertical, .navbar-top, .app-banners, .app-breadcrumbs, .d-print-none { display: none !important; }
  .content { margin: 0 !important; padding: 0 !important; }
}

/* Reports on a phone (ticket 0184) ---------------------------------------------------------------------------------- */
/* A report's figure tiles sit two to a row below 576px, their numbers sized to fit half a 390px screen */
@media (max-width: 575.98px) {
  .report-tiles > [class*="col-"] { flex: 0 0 auto; width: 50%; }
  .report-tiles .display-5, .report-tiles .display-6, .report-tiles .fs-2, .report-tiles .fs-7 { font-size: var(--fs-20) !important; }
  .report-tiles .card-body { padding: var(--space-3); }
}
/* A report's table is a stack of row cards below 576px, as .table-stack-md is below 768px: each row a card, each cell
   a line with its heading from data-label, the row's title cell across the top */
@media (max-width: 575.98px) {
  .table-stack-sm thead, .table-stack-sm tfoot td:empty { display: none; }
  .table-stack-sm, .table-stack-sm tbody, .table-stack-sm tfoot, .table-stack-sm tr, .table-stack-sm td { display: block; width: 100%; }
  .table-stack-sm tr {
    margin: var(--space-2);
    width: auto;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
  }
  .table-stack-sm td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-1) 0;
    border: 0;
    text-align: right !important;
  }
  .table-stack-sm td[data-label]::before {
    content: attr(data-label);
    color: var(--text-muted);
    text-align: left;
    flex: 0 0 auto;
  }
  .table-stack-sm td[style] { width: 100% !important; }
  .table-stack-sm td > .progress { flex: 1 1 auto; max-width: 60%; }
  .table-stack-sm td.table-stack-title, .table-stack-sm td[colspan] { display: block; text-align: left !important; }
  .table-stack-sm td.table-stack-title { font-size: 1.05em; }
  .table-stack-sm td.table-stack-actions { justify-content: flex-end; padding-top: var(--space-2); }
  /* A card's own scroll is not needed once its rows are cards: nothing is wider than the screen */
  .table-responsive:has(> .table-stack-sm) { overflow-x: visible; }
}

/* layouts/full's Switch back while impersonating (partials/impersonation-switch-back): one small control in the
   bottom-left corner of the full-bleed designer and map, under the designer's toolbar and clear of its welcome card */
.impersonation-switch-back { position: fixed; left: 10px; bottom: 16px; z-index: 2050; margin: 0; }

/* The designer's editing bar (ticket 0208): a demo location opened from Admin → Demo locations says what is being
   edited, sets the start view and goes back to admin. A strip of its own above the designer, in the page's flow, so
   it never covers the page's title (the site's address, top left) or the canvas's own overlays at any width (the
   0208 dev walk: floated over the top centre, it cut the address off) */
.demo-editing-bar {
  display: flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--demo-editing-bar-height); margin: 0; padding: 0 var(--space-3); overflow: hidden;
  background: var(--frame-solid); color: var(--on-frame-solid); font-size: var(--fs-14); white-space: nowrap;
}
.demo-editing-bar__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.demo-editing-bar > * { flex-shrink: 0; }
.demo-editing-bar > .demo-editing-bar__name { flex-shrink: 1; }
.demo-editing-bar form { margin: 0; }
body:has(.demo-editing-bar) { --demo-editing-bar-height: 44px; }
/* The overlays placed from the top of the page (the menu's logo, the title, the way back, the settings cog, and the
   tools under the title: moved alone, the title ran under them) move down with the canvas, under the bar */
body:has(.demo-editing-bar) .toggle-icon-wrapper,
body:has(.demo-editing-bar) #titlebar,
body:has(.demo-editing-bar) #toolbar,
body:has(.demo-editing-bar) #backtoproject,
body:has(.demo-editing-bar) #settingsbutton { translate: 0 var(--demo-editing-bar-height); }
@media (max-width: 576px) {
  .demo-editing-bar { font-size: var(--fs-12); }
  .demo-editing-bar__what { display: none; }
}

/* ==========================================================================
 * Options side by side on a quote's page (ticket 0011)
 * ========================================================================== */
.quote-options { list-style: none; margin: 0; padding: 0; }
.quote-options__row { display: grid; grid-template-columns: 2rem minmax(0, 1fr) auto auto; align-items: center; gap: 0.75rem;
  padding: 0.55rem 0; border-bottom: 1px solid var(--border); }
.quote-options__row:last-child { border-bottom: 0; }
.quote-options__letter { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border-radius: 50%;
  background: var(--bg-subtle, #eef0f2); font-weight: 600; }
.quote-options__row.is-here .quote-options__letter { background: var(--primary, #2563eb); color: #fff; }
.quote-options__price { font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 576px) {
  .quote-options__row { grid-template-columns: 2rem minmax(0, 1fr); }
  .quote-options__price, .quote-options__row .badge { grid-column: 2; justify-self: start; }
}
