/* ------------------------------------------------------------------
   evoHouse.css - the house components of the modernized look
   (docs-dev/styling.inc; house plan section 7.2, ruled 07-10-2026).

   Every component another page could use lives here under a generic
   evo- class name, loaded globally from index.php straight after
   style.css. Pages hold markup only: no <style> copy and no
   page-prefixed copy (rq-, or-, tk-...) of a house component, so a
   change to the house design is one edit here, not an audit of every
   page. Truly page-specific rules go in assets/css/modules/<page>.css.
   ------------------------------------------------------------------ */
/* View chips (docs-dev/styling.inc 1.4f): a one-line strip of filter buttons with
   counts - the register's status buckets, a workspace's saved views. Exactly one
   is .active (filled primary); clicking it again clears back to all. The count
   sits in a pill; .is-warning / .is-danger tint that pill so a bucket that is a
   problem reads as one without a tile row. .is-empty fades a bucket with nothing
   in it. Adopted by reqreg and opportunityWorkspace (chips, saved views, phone stage strip). */
.evo-vchips { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; }
.evo-vchip {
	display: inline-flex;
	align-items: center;
	gap: .4rem;
	border: 1px solid #ced4da;
	background: #fff;
	color: #212529;
	border-radius: 1rem;
	padding: .22rem .35rem .22rem .85rem;
	font-size: .95rem;
	line-height: 1.4;
	white-space: nowrap;
	cursor: pointer;
}
.evo-vchip:hover { background: #f1f3f5; }
.evo-vchip:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 1px; }
.evo-vchip.active { background: var(--bs-primary); border-color: var(--bs-primary); color: #fff; }
.evo-vchip-n {
	display: inline-block;
	min-width: 1.6em;
	padding: 0 .45rem;
	border-radius: 1rem;
	background: #e9ecef;
	color: #495057;
	font-weight: 600;
	font-size: .875rem;
	text-align: center;
	font-variant-numeric: tabular-nums;
}
.evo-vchip.is-warning .evo-vchip-n { background: #fff3cd; color: #664d03; }
.evo-vchip.is-danger .evo-vchip-n { background: #f8d7da; color: #842029; }
.evo-vchip.active .evo-vchip-n { background: rgba(255,255,255,.25); color: #fff; }
.evo-vchip-sub { opacity: .75; padding-right: .3rem; }
.evo-vchip-sub:empty { display: none; }
.evo-vchip.is-empty { opacity: .6; }
.evo-vchip.is-empty .evo-vchip-n { background: #e9ecef; color: #495057; }
/* Toggle-chip group (candidate 14-10-2026, jobregister "Focus"): on/off chips that sit
   in the view-chip row but are a different kind of control - any mix may be on, and
   they narrow whichever view is picked. Boxed and labelled so they read as one set,
   and "on" is a tinted chip with a tick, never the view chip's solid fill.
     <div class="evo-vchips-group" role="group" aria-label="...">
       <span class="evo-vchips-label">Focus</span>
       <button type="button" class="evo-vchip [active]" aria-pressed="...">Label <span class="evo-vchip-n">3</span></button>
     </div> */
.evo-vchips-group {
	display: flex; flex-wrap: wrap; align-items: center; gap: .45rem;
	padding: .2rem .3rem .2rem .7rem;
	border: 1px dashed #adb5bd; border-radius: 1.3rem; background: #f8f9fa;
}
.evo-vchips-label { font-size: .75rem; letter-spacing: .04em; text-transform: uppercase; color: #6c757d; }
.evo-vchips-group .evo-vchip.active { background: #e7f1ff; border-color: var(--bs-primary); color: #084298; }
.evo-vchips-group .evo-vchip.active::before { content: "\2713"; font-weight: 700; margin-right: -.15rem; }
.evo-vchips-group .evo-vchip.active .evo-vchip-n { background: var(--bs-primary); color: #fff; }

/* Brand mark: a party's logo, or its initials on its brand colour when it has none.
   First users: carriers (register, dispatch Freight & Tracking card, Shipping hub);
   generic so suppliers or plugins can reuse it. PHP Carriers::badge() and JS
   evoBrandBadge() (global.js) print the same markup.
   <span class="evo-brand"><img class="evo-brand-logo" ...> Name</span>
   <span class="evo-brand"><span class="evo-brand-mono" style="background:#d40511;color:#fff">AP</span> Name</span>
   Size: default 20px for register rows, add .evo-brand-md (32px) for a record card. */
.evo-brand {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	min-width: 0;
	vertical-align: middle;
}
.evo-brand-logo {
	display: inline-block;
	height: 20px;
	width: auto;
	max-width: 96px;
	object-fit: contain;
	object-position: left center;
	flex: 0 0 auto;
	vertical-align: middle;
}
.evo-brand-mono {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	height: 20px;
	min-width: 20px;
	padding: 0 .3rem;
	border-radius: .3rem;
	background: #6c757d;
	color: #fff;
	font-size: .7rem;
	font-weight: 700;
	line-height: 1;
	letter-spacing: .02em;
	vertical-align: middle;
	user-select: none;
}
.evo-brand-logo.evo-brand-md { height: 32px; max-width: 160px; }
.evo-brand-mono.evo-brand-md { height: 32px; min-width: 32px; padding: 0 .45rem; font-size: .85rem; border-radius: .4rem; }
/* View-chip extras: .is-plain evens the padding on a chip with no count pill
   (a workspace's "All open" or a saved view); .evo-vchip-x is the delete
   cross on a chip the user owns (a saved view). The click handler checks
   data-delete on the cross before treating the click as a filter. */
.evo-vchip.is-plain { padding-right: .85rem; }
.evo-vchip-x { font-size: 1.077rem; opacity: .7; margin-left: -.15rem; margin-right: .1rem; }
.evo-vchip-x:hover { opacity: 1; }

/* Filter tile (docs-dev/styling.inc 1.4b): a stat card that IS a filter, on
   workspaces and dashboards only (registers use view chips). Goes on the 1.4a
   accent card with a data-* filter value and a title=. The active state is the
   outline ring (.kpi-active), so the accent left edge keeps its meaning. A
   read-only stat card in the same row just leaves the class off. */
.evo-ftile { cursor: pointer; }
.evo-ftile:hover { box-shadow: 0 .5rem 1rem rgba(0,0,0,.15) !important; }
.evo-ftile.kpi-active { outline: 2px solid var(--bs-primary); outline-offset: 1px; }
.evo-ftile .h4 { white-space: nowrap; }

/* Due badge: a next step or task with its due state. Grey when it is due later,
   .is-today amber, .is-over red. Truncates to its cell; put the full wording and
   date in title=. */
.evo-due { display: inline-block; border-radius: .25rem; padding: 0 .3rem; background: #f1f3f5; white-space: nowrap;
	max-width: 100%; overflow: hidden; text-overflow: ellipsis; vertical-align: bottom; }
.evo-due.is-today { background: #fff3cd; color: #664d03; }
.evo-due.is-over { background: #f8d7da; color: #842029; }
/* .is-none: nothing is scheduled and something should be ("No next step") */
.evo-due.is-none { background: transparent; color: #842029; font-style: italic; padding: 0; }

/* Segment dot: a customer segment as its colour dot plus its name. Set the colour
   on the <i> inline from the segment's own colour; grey when it has none. */
.evo-seg { display: inline-flex; align-items: center; gap: .2rem; font-size: .72rem; color: #495057; white-space: nowrap; margin-right: .4rem; }
.evo-seg i { width: .55rem; height: .55rem; border-radius: 50%; display: inline-block; background: #6c757d; }

/* Group band (docs-dev/styling.inc 5.6): the header row over a group of lines.
   <tr class="evo-gband"><td colspan="N">Name <span class="evo-gband-sum">3 lines
   &middot; $1,200</span></td></tr>. The name is the small uppercase muted
   mini-label; the summary after it reads in normal case. */
tr.evo-gband > td {
	background: #f1f3f5;
	border-bottom: 1px solid #dee2e6;
	padding-top: .3rem;
	padding-bottom: .3rem;
	vertical-align: middle;
	font-size: .875em;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .03em;
	color: #6c757d;
}
.evo-gband-sum { font-weight: 400; text-transform: none; letter-spacing: 0; margin-left: .5rem; }

/* Sortable header: <th class="evo-sort" data-sort="key">Label</th>. The page JS
   appends <i class="material-symbols-rounded evo-sort-ico">unfold_more</i>
   (arrow_upward / arrow_downward on the sorted column) and sets aria-sort
   ="ascending" | "descending" on the sorted column only. The label never wraps
   (styling 3). */
th.evo-sort { cursor: pointer; white-space: nowrap; user-select: none; }
/* color: inherit - the global icon grey vanishes on a thead-dark header (branchreg) */
th.evo-sort .evo-sort-ico { font-size: 1.231rem; vertical-align: -3px; opacity: .45; color: inherit; }
th.evo-sort[aria-sort] .evo-sort-ico { opacity: 1; }

/* Register column roles (docs-dev/styling.inc 3, ruled 08-10-2026). A table becomes
   .evo-fit when its header row carries a role (assets/js/evoTableFit.js adds the
   class). Every column is one line at its content width (width:1% shrinks it to
   that); th.evo-col-text columns share what is left by their data-weight and cut
   to one line with an ellipsis. th.evo-col-wrap record cells may go to two lines
   when the table would otherwise overflow. The per-column rules are generated by the
   script, because CSS cannot style a <td> from its <th>'s class. Rows with a
   colspan (group bands, loading and empty messages) are left alone. */
table.evo-fit { width: 100%; }
table.evo-fit > * > tr > :not([colspan]) { white-space: nowrap; width: 1%; }
/* Numbers (docs-dev/styling.inc 1.7): tabular digits so a money or quantity column
   lines up. Cell: class="text-end text-nowrap num". Alignment stays with text-end, so
   the older .num cells that never set it are unaffected beyond the digit widths. */
.num { font-variant-numeric: tabular-nums; }

/* Sticky action bar (docs-dev/styling.inc 5.2): the bar that holds a page's
   actions, or the bulk actions for ticked rows, pinned to the bottom of the
   window while the list scrolls. Markup: d-flex flex-wrap align-items-center
   gap-2 border rounded bg-white px-3 py-2. A bulk bar starts hidden and the JS
   shows it with display:flex when something is ticked (1.10b). */
.evo-actionbar { position: sticky; bottom: 8px; z-index: 5; box-shadow: 0 -2px 12px rgba(0,0,0,.15); }

/* Full-screen modal on phones: no class here. Use Bootstrap's own
   modal-fullscreen-md-down on the .modal-dialog. */

/* Kanban board (docs-dev/styling.inc 7.4, ruled 08-10-2026): a column per stage,
   cards dragged between columns, Won/Lost drop zones while dragging. Workspaces
   only (page type Workspaces / Boards). Markup:
   <div class="evo-board-wrap">                        .is-dragging while a card moves
     <div class="evo-board-strip evo-vchips"></div>     phone: a chip per column
     <div class="evo-board">
       <div class="evo-board-col">
         <div class="evo-board-head"><span class="evo-board-name">Stage</span> count
           <div class="evo-board-sums">$ . weighted $ . %</div>
           <div class="evo-board-share"><span style="width:N%"></span></div></div>
         <div class="evo-board-cards"> a.evo-kcard ... </div>
       </div>
     </div>
     <div class="evo-board-drop"><div class="evo-board-dropzone is-success">Won
       <div class="evo-board-cards"></div></div> ... </div>
   </div>
   Set --evo-board-max on .evo-board-wrap when the page header is taller or
   shorter than the workspace's. */
.evo-board { display: flex; gap: .75rem; overflow-x: auto; padding-bottom: .5rem; align-items: flex-start; }
.evo-board-col { flex: 0 0 280px; background: #f1f3f5; border-radius: .5rem; display: flex; flex-direction: column;
	max-height: var(--evo-board-max, calc(100vh - 260px)); }
.evo-board-head { padding: .5rem .6rem .4rem; border-bottom: 1px solid #dee2e6; }
.evo-board-name { font-weight: 600; text-transform: uppercase; font-size: .8rem; }
.evo-board-sums { font-size: .8rem; color: #6c757d; }
/* the column's share of the board's value */
.evo-board-share { height: 4px; background: #dee2e6; border-radius: 2px; margin-top: .3rem; }
.evo-board-share > span { display: block; height: 4px; border-radius: 2px; background: var(--bs-primary); }
.evo-board-cards { padding: .5rem; overflow-y: auto; min-height: 60px; flex: 1 1 auto; }
.evo-board-more { width: 100%; }
/* jQuery UI sortable placeholder: placeholder: 'evo-board-placeholder' */
.evo-board-placeholder { border: 2px dashed #adb5bd; border-radius: .4rem; height: 70px; margin-bottom: .5rem; }
/* Drop zones: hidden until a drag starts; .is-over while a card hovers one */
.evo-board-drop { display: none; position: fixed; left: 50%; bottom: 1rem; transform: translateX(-50%); z-index: 1050; gap: 1rem; }
.evo-board-wrap.is-dragging .evo-board-drop { display: flex; }
.evo-board-dropzone { width: 220px; height: 70px; border: 2px dashed; border-radius: .5rem; display: flex; align-items: center;
	justify-content: center; font-weight: 600; background: rgba(255,255,255,.95); box-shadow: 0 .5rem 1rem rgba(0,0,0,.15); position: relative; }
/* The sortable target: an invisible layer over the whole zone. display:none gave
   jQuery UI nothing to drop onto, so Won / Lost and Close / Void never took a
   card (found 26-10-2026). */
.evo-board-dropzone .evo-board-cards { position: absolute; inset: 0; overflow: hidden; opacity: 0; }
.evo-board-dropzone.is-success { border-color: var(--bs-success); color: var(--bs-success); }
.evo-board-dropzone.is-secondary { border-color: var(--bs-secondary); color: var(--bs-secondary); }
.evo-board-dropzone.is-over { background: #e9ecef; }
.evo-board-strip { display: none; }

/* Kanban card: the whole card is a link to the record. Owner initials and the
   actions menu sit top right; .is-rotting (too long in its stage, 1.8) is the
   red left edge plus a red age bar. Rows: title, customer (-sub), tags, value
   and close date, next step (.evo-due). */
.evo-kcard { display: block; background: #fff; border: 1px solid #dee2e6; border-left: 3px solid transparent; border-radius: .4rem;
	padding: .45rem .55rem .35rem; margin-bottom: .5rem; color: inherit; text-decoration: none; position: relative; cursor: grab; }
.evo-kcard:hover { box-shadow: 0 .25rem .5rem rgba(0,0,0,.12); color: inherit; }
.evo-kcard.is-rotting { border-left-color: var(--bs-danger); }
.evo-kcard-title { font-weight: 600; font-size: .9rem; padding-right: 3.2rem; line-height: 1.25; }
.evo-kcard-sub { font-size: .8rem; color: #6c757d; }
.evo-kcard-row { display: flex; align-items: center; gap: .4rem; font-size: .8rem; margin-top: .2rem; flex-wrap: wrap; }
.evo-kcard-who { position: absolute; top: .4rem; right: 1.8rem; width: 1.5rem; height: 1.5rem; border-radius: 50%; background: #e7f1ff;
	color: #0a58ca; font-size: .65rem; font-weight: 700; display: flex; align-items: center; justify-content: center; }
.evo-kcard-menu { position: absolute; top: .3rem; right: .2rem; border: 0; background: transparent; padding: 0 .1rem; color: #6c757d; line-height: 1; }
/* days in stage against the stage's limit */
.evo-kcard-age { height: 3px; background: #e9ecef; border-radius: 2px; margin-top: .35rem; }
.evo-kcard-age > span { display: block; height: 3px; border-radius: 2px; background: #adb5bd; }
.evo-kcard.is-rotting .evo-kcard-age > span { background: var(--bs-danger); }

/* Phone: one column per screen with snap, a chip strip to jump between columns,
   tap opens the card (no drag, no drop zones, no age bar) */
@media (max-width: 767.98px) {
	.evo-board { scroll-snap-type: x mandatory; gap: .5rem; }
	.evo-board-col { flex: 0 0 calc(100% - 24px); scroll-snap-align: start; max-height: none; } /* % of the board, not the viewport: the side nav is still showing */
	.evo-board-strip { display: flex; flex-wrap: nowrap; gap: .4rem; overflow-x: auto; margin-bottom: .5rem; }
	.evo-board-drop { display: none !important; }
	.evo-kcard { cursor: pointer; }
	.evo-kcard-age { display: none; }
}

/* Label links and selectFilter icons (docs-dev/styling.inc 1.9a, ruled 11-10-2026).
   A link at the right of a field label goes to the record the field points at
   (Project -> the project, Address -> the map). A span with the class is a
   status that has no link ("Not located").
   <div class="d-flex align-items-center"><label class="form-label ...">Project</label>
     <a href="..." class="evo-label-link ms-auto">Go to project <i class="material-symbols-rounded">arrow_forward</i></a></div> */
.evo-label-link { font-size: .75rem; margin-bottom: .1rem; white-space: nowrap; }
span.evo-label-link { cursor: default; }
.evo-label-link .material-symbols-rounded { font-size: .95rem; vertical-align: -3px; }
/* A read-only way to reach someone: icon, value, then label links (Call / Email / Map, Copy).
   <div class="evo-reach d-flex align-items-center gap-2 small"><i class="material-symbols-rounded">call</i>
     <span>0400 000 000</span><a class="evo-label-link ms-auto" href="tel:...">Call ...</a></div> */
.evo-reach > .material-symbols-rounded { font-size: 1.05rem; color: #6c757d; }
/* A selectFilter always keeps its search icon; in a small group, size it to the inputs. */
.input-group-sm > .input-group-text:has(> .material-symbols-rounded) { padding-block: 0; }
.input-group-sm > .input-group-text > .material-symbols-rounded { font-size: 1.05rem; }

/* Record page: header band, key figures, panels and the working grid
   (docs-dev/styling.inc 5.2a, 5.5, 6.3; consolidation inventory B). The band is
   shared by dispatchedit, reqedit, ticketedit and opportunityRecord (11-10-2026):
   change it here, never in a page.

   Band: the record's name, state and context, with its actions on the right.
   <div class="evo-band mb-2 mt-1"><div class="d-flex flex-wrap align-items-start gap-2">
     <div class="evo-band-main">
       <div class="d-flex align-items-center flex-wrap gap-2"><h1 class="evo-band-name">Name</h1> pill flags</div>
       <div class="evo-band-sub mt-1">Record 12 &middot; project link &middot; customer</div>
     </div>
     <div class="evo-band-actions d-flex flex-wrap gap-1"> buttons, More dropdown </div>
   </div></div> */
/* clear: the page header's .pagebutton groups float right and, on a phone, hang over the band's top. */
.evo-band { background: #fff; border: 1px solid #dee2e6; border-radius: .5rem; padding: .75rem 1rem; clear: both; }
/* A basis, not just grow: without it the actions squeeze the name to nothing on a phone; with it they wrap below. */
.evo-band-main { flex: 1 1 16rem; min-width: 0; }
.evo-band-name { font-size: 1.35rem; font-weight: 600; line-height: 1.25; margin: 0; overflow-wrap: anywhere; }
.evo-band-name.is-untitled { color: #6c757d; font-weight: 500; }
.evo-band-sub { color: #6c757d; font-size: .9rem; }
.evo-band-sub a { color: inherit; }
.evo-band-actions .btn { white-space: nowrap; }
.evo-band-actions .material-symbols-rounded, .evo-band-actions .dropdown-item .material-symbols-rounded,
.evo-actionbar .btn .material-symbols-rounded { font-size: 1.2rem; vertical-align: -4px; }
/* A flag that opens something (the signature behind "Signed") */
.evo-band a.evo-band-flag { text-decoration: none; }
@media (max-width: 767.98px) { .evo-band-name { font-size: 1.15rem; } }

/* Click-to-edit (styling.inc 6.4): a value that turns into an input when clicked and saves
   on Enter / leaving the box (evoInlineEdit() in global.js). Never on a locked record.
   <h1 class="evo-band-name evo-editable" role="button" tabindex="0" title="Click to rename">Name</h1>
   The dashed underline is the cue; in a title it is text-decoration so it follows a wrapped line. */
.evo-editable { cursor: pointer; border-bottom: 1px dashed #adb5bd; }
.evo-editable:hover { border-bottom-color: #495057; }
.evo-band-name.evo-editable { border-bottom: 0; text-decoration: underline dashed #adb5bd 1px; text-underline-offset: .3em; }
.evo-band-name.evo-editable:hover { text-decoration-color: #495057; }
.evo-inline-input { width: 100%; }
.evo-band .evo-inline-input { font-size: 1.15rem; font-weight: 600; padding: .1rem .5rem; width: auto; flex: 1 1 18rem; max-width: 36rem; }

/* Steps (candidate, 12-10-2026, first used on dispatchedit's Freight tab; not yet a
   styling.inc rule): a tab whose job is a sequence. Every step stays open; the head
   says whether it is done. data-state: done (green tick), todo, warn (amber), na
   (optional / does not apply). .is-current marks the first todo / warn step.
   <div class="evo-step" data-state="todo"><div class="evo-step-head">
     <span class="evo-step-num">1</span><span class="evo-step-title">How it goes</span>
     <span class="evo-step-status">Choose how it goes</span></div>
   <div class="evo-step-body">...</div></div> */
.evo-step { border: 1px solid #dee2e6; border-radius: .5rem; background: #fff; margin-bottom: .6rem; }
.evo-step.is-current { border-color: var(--main-highlight-color, var(--bs-primary)); }
.evo-step-head { display: flex; align-items: center; gap: .6rem; padding: .5rem .75rem; border-bottom: 1px solid #f1f3f5; flex-wrap: wrap; }
.evo-step-num { flex: 0 0 auto; width: 1.7rem; height: 1.7rem; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: .85rem; font-weight: 600; border: 1.5px solid #adb5bd; color: #6c757d; background: #fff; }
.evo-step.is-current .evo-step-num { border-color: var(--main-highlight-color, var(--bs-primary)); color: var(--main-highlight-color, var(--bs-primary)); }
.evo-step[data-state="done"] .evo-step-num { border-color: #198754; background: #198754; color: #fff; }
.evo-step[data-state="warn"] .evo-step-num { border-color: #ffc107; background: #ffc107; color: #212529; }
.evo-step-num .material-symbols-rounded { font-size: 1.15rem; color: inherit; font-variation-settings: "FILL" 1, "wght" 700, "GRAD" 0, "opsz" 20; }
.evo-step-title { font-weight: 600; }
.evo-step-status { margin-left: auto; font-size: .85rem; color: #6c757d; text-align: right; min-width: 0; overflow-wrap: anywhere; }
.evo-step[data-state="done"] .evo-step-status { color: #146c43; }
.evo-step[data-state="warn"] .evo-step-status { color: #997404; font-weight: 600; }
.evo-step-body { padding: .6rem .75rem .5rem; }
@media (max-width: 575.98px) { .evo-step-status { margin-left: 2.3rem; flex-basis: 100%; text-align: left; } }

/* Stage tracker (styling.inc 6.5, ruled 13-10-2026): chevrons, one per step, rendered by
   Status::track() and kept live by evoTrackSet() (global.js). data-state: done (green tint),
   todo (grey), warn (amber), danger (red), skip (faded: does not apply). .is-current is
   filled. A step with a .evo-track-go button is clickable. .evo-track-sm = compact, no notes.
   <ol class="evo-track" aria-label="Progress"><li class="evo-track-step is-current" data-state="todo">
     <span class="evo-track-label">Details</span><span class="evo-track-note">Add activity</span></li></ol> */
.evo-track { display: flex; gap: 2px; list-style: none; padding: 0; margin: 0; }
.evo-track-step { flex: 1 1 0; min-width: 0; background: #e9ecef; color: #495057; font-size: .8rem; line-height: 1.25;
	padding: .35rem .9rem .32rem 1.15rem;
	clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 50%, calc(100% - 10px) 100%, 0 100%, 10px 50%); }
.evo-track-step:first-child { padding-left: .7rem; clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 50%, calc(100% - 10px) 100%, 0 100%); }
.evo-track-label { display: block; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.evo-track-note { display: block; font-size: .72rem; opacity: .85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.evo-track-step[data-state="done"] { background: #d1e7dd; color: #0a3622; }
.evo-track-step[data-state="warn"] { background: #fff3cd; color: #664d03; }
.evo-track-step[data-state="danger"] { background: #f8d7da; color: #842029; }
.evo-track-step[data-state="skip"] { background: #f8f9fa; color: #adb5bd; }
.evo-track-step.is-current { background: var(--main-highlight-color, var(--bs-primary)); color: #fff; }
.evo-track-step.is-current[data-state="warn"] { background: #ffc107; color: #212529; }
.evo-track-step.is-current[data-state="danger"] { background: var(--bs-danger); color: #fff; }
.evo-track-go { display: block; width: 100%; padding: 0; margin: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.evo-track-go:focus-visible { outline: 2px solid currentColor; outline-offset: -2px; }
.evo-track-step:has(.evo-track-go):hover { filter: brightness(.95); }
.evo-track-sm .evo-track-step { font-size: .7rem; padding: .2rem .55rem .2rem .85rem; }
.evo-track-sm .evo-track-step:first-child { padding-left: .5rem; }
.evo-track-sm .evo-track-label { font-weight: 500; }
.evo-track-sm .evo-track-step.is-current .evo-track-label { font-weight: 700; }
@media (max-width: 575.98px) {
	.evo-track:not(.evo-track-sm) { flex-wrap: wrap; row-gap: 2px; }
	.evo-track:not(.evo-track-sm) .evo-track-step { flex: 1 1 calc(33.333% - 2px); }
}

/* Activity timeline (styling.inc 6.6, ruled 13-10-2026): a rail with one tinted icon circle
   per entry, newest first. Rendered by Timeline::render() (library/Timeline.php) or, for
   loaded/paged lists, evoTimelineItem() (global.js) - same markup, same field names.
   data-kind picks the icon and tint (Timeline::KINDS). .is-current rings the circle (the
   span that is still running). Body text keeps its line breaks; .is-html bodies are
   logNoteHtml() output. .is-clamped cuts a long body with a "Show all" (.evo-tl-more).
   Filter chips are .evo-vchips; "Show older" paging is the page's own endpoint.
   .evo-timeline-sm = side-panel size.
   <ol class="evo-timeline" aria-label="History"><li class="evo-tl-item" data-kind="note">
     <span class="evo-tl-ico" aria-hidden="true"><i class="material-symbols-rounded">sticky_note_2</i></span>
     <div class="evo-tl-main"><div class="evo-tl-head"><span class="evo-tl-title">Note</span>
       <span class="evo-tl-meta">25 Oct 14:02 · Shane</span></div><div class="evo-tl-body">...</div></div></li></ol> */
.evo-timeline { list-style: none; margin: 0; padding: 0; }
.evo-tl-item { position: relative; display: flex; gap: .65rem; padding: .45rem 0; }
.evo-tl-item[hidden] { display: none; }
.evo-tl-item::before { content: ''; position: absolute; left: calc(.962rem - 1px); top: 0; bottom: 0; width: 2px; background: #e9ecef; }
.evo-tl-item:first-child::before { top: 1.4rem; }
.evo-tl-item:last-child::before { bottom: auto; height: 1.4rem; }
.evo-tl-item:only-child::before { display: none; }
.evo-tl-ico { position: relative; z-index: 1; flex: 0 0 1.923rem; width: 1.923rem; height: 1.923rem; border-radius: 50%;
	display: flex; align-items: center; justify-content: center; background: #e9ecef; color: #495057; box-shadow: 0 0 0 3px #fff; }
.evo-tl-ico .material-symbols-rounded { font-size: 1.308rem; }
.evo-tl-item[data-kind="note"] .evo-tl-ico { background: #fff3cd; color: #664d03; }
.evo-tl-item[data-kind="task"] .evo-tl-ico { background: #e7f1ff; color: #0a58ca; }
.evo-tl-item[data-kind="call"] .evo-tl-ico, .evo-tl-item[data-kind="meeting"] .evo-tl-ico { background: #d1e7dd; color: #0f5132; }
.evo-tl-item[data-kind="quote"] .evo-tl-ico { background: #e2d9f3; color: #432874; }
.evo-tl-item[data-kind="file"] .evo-tl-ico, .evo-tl-item[data-kind="email"] .evo-tl-ico { background: #cff4fc; color: #055160; }
.evo-tl-item[data-kind="start"] .evo-tl-ico { background: #d1e7dd; color: #0a3622; }
.evo-tl-item.is-current .evo-tl-ico { background: #e7f1ff; color: #084298; box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--main-highlight-color, var(--bs-primary)); }
.evo-tl-main { flex: 1 1 auto; min-width: 0; }
.evo-tl-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem .5rem; padding-top: .3rem; }
.evo-tl-title { font-weight: 600; font-size: .88rem; overflow-wrap: anywhere; }
.evo-tl-item[data-kind="change"] .evo-tl-title { font-weight: 400; color: #495057; }
.evo-tl-meta { margin-left: auto; font-size: .75rem; color: #6c757d; white-space: nowrap; }
.evo-tl-act { flex: 0 0 auto; align-self: center; padding: 0; border: 0; background: none; color: #6c757d; line-height: 1; }
.evo-tl-act .material-symbols-rounded { font-size: 1.385rem; }
.evo-tl-act:hover { color: #212529; }
.evo-tl-body { font-size: .85rem; white-space: pre-line; overflow-wrap: anywhere; margin-top: .1rem; }
.evo-tl-body.is-html { white-space: normal; }
.evo-tl-body img { max-width: 100%; }
.evo-tl-body.is-clamped { max-height: 7.5em; overflow: hidden; }
.evo-tl-more { display: inline-block; padding: 0; border: 0; background: none; font-size: .8rem; color: var(--bs-link-color, var(--bs-primary)); text-decoration: underline; }
.evo-tl-thumb { display: block; max-width: 160px; max-height: 110px; margin-top: .3rem; border: 1px solid #dee2e6; border-radius: .3rem; }
.evo-tl-older { margin-top: .5rem; }
.evo-timeline-sm .evo-tl-item { gap: .5rem; padding: .3rem 0; }
.evo-timeline-sm .evo-tl-item::before { left: calc(.692rem - 1px); }
.evo-timeline-sm .evo-tl-item:first-child::before { top: 1rem; }
.evo-timeline-sm .evo-tl-item:last-child::before { height: 1rem; }
.evo-timeline-sm .evo-tl-ico { flex-basis: 1.385rem; width: 1.385rem; height: 1.385rem; box-shadow: 0 0 0 2px #fff; }
.evo-timeline-sm .evo-tl-ico .material-symbols-rounded { font-size: .923rem; }
.evo-timeline-sm .evo-tl-item.is-current .evo-tl-ico { box-shadow: 0 0 0 2px #fff, 0 0 0 3px var(--main-highlight-color, var(--bs-primary)); }
.evo-timeline-sm .evo-tl-head { padding-top: 0; }
.evo-timeline-sm .evo-tl-title { font-size: .85rem; }
/* Meta on its own line: it moves after the action, which keeps the title line (right). */
.evo-timeline-sm .evo-tl-meta { margin-left: 0; flex-basis: 100%; white-space: normal; order: 1; }
.evo-timeline-sm .evo-tl-act { margin-left: auto; }
@media (max-width: 575.98px) {
	.evo-tl-meta { margin-left: 0; flex-basis: 100%; white-space: normal; order: 1; }
	.evo-tl-act { margin-left: auto; }
}

/* Key figures (1.4c): a row of read-only tiles under the band.
   <div class="row g-2 mb-2"><div class="col-6 col-md-4 col-xl-2"><div class="evo-fig">
     <div class="evo-fig-lbl">Lines</div><div class="evo-fig-val">12</div><div class="evo-fig-note">3 short</div>
   </div></div></div>
   Only an exception tile gets border-warning / border-danger. .is-link (with
   role="button" tabindex="0" and a title=) is a tile that opens a tab. */
.evo-fig { background: #fff; border: 1px solid #dee2e6; border-radius: .5rem; padding: .5rem .75rem; height: 100%; }
.evo-fig.border-warning { border-color: var(--bs-warning) !important; }
.evo-fig.border-danger { border-color: var(--bs-danger) !important; }
.evo-fig-lbl { font-size: .72rem; text-transform: uppercase; color: #6c757d; }
.evo-fig-val { font-size: 1.15rem; font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; }
.evo-fig-note { font-size: .78rem; color: #6c757d; }
.evo-fig.is-link { cursor: pointer; }
.evo-fig.is-link:hover, .evo-fig.is-link:focus-visible { border-color: var(--main-highlight-color, var(--bs-primary)); outline: none; }
@media (max-width: 575.98px) { .evo-fig-val { font-size: .95rem; } .evo-fig { padding: .4rem .55rem; } }

/* Panel: one concern of the record (Details, Notes...). The h6 is optional.
   <div class="evo-panel"><h6><i class="material-symbols-rounded">tune</i> Details</h6><div class="evo-panel-body">...</div></div>
   Field labels inside: form-label text-muted text-uppercase small mb-1. */
.evo-panel { background: #fff; border: 1px solid #dee2e6; border-radius: .5rem; margin-bottom: .75rem; }
.evo-panel > h6 { font-size: .75rem; text-transform: uppercase; color: #6c757d; letter-spacing: .03em; margin: 0; padding: .55rem .75rem .35rem;
	display: flex; align-items: center; gap: .4rem; }
.evo-panel > h6 .material-symbols-rounded { font-size: 1.1rem; }
.evo-panel-body { padding: .6rem .75rem .7rem; font-size: .88rem; }
.evo-panel > h6 + .evo-panel-body { padding-top: .25rem; }

/* Map tab: a Google map beside a side panel of .evo-panel cards. The canvas holds an
   .evo-map-msg until the map loads (and instead of it when Google refuses).
   <div class="evo-map" id="xMapCanvas"><div class="evo-map-msg">Loading the map...</div></div>
   Layer colours live here, on .evo-map-dot; the page JS reads them for its markers so
   the legend and the pins can't drift apart. */
.evo-map { height: 520px; border: 1px solid #dee2e6; border-radius: .5rem; background: #f8f9fa; overflow: hidden; }
.evo-map-msg { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .5rem;
	padding: 1rem; text-align: center; color: #6c757d; font-size: .875rem; }
.evo-map-dot { display: inline-block; width: .7rem; height: .7rem; border-radius: 50%; border: 1px solid rgba(0, 0, 0, .25); vertical-align: -1px; background: #6c757d; }
.evo-map-dot.is-branch { background: #dc3545; }
.evo-map-dot.is-project { background: #0d6efd; }
.evo-map-dot.is-opp { background: #fd7e14; }
.evo-map-dot.is-lead { background: #6f42c1; }
.evo-map-dot.is-defect { background: #20c997; }
@media (max-width: 991.98px) { .evo-map { height: 360px; } }

/* Working grid (5.2a): the lines table in its own scroll box sized to the window,
   so the heading row and the total row stay in view. Not .table-responsive: sticky
   cells would stick to a box that never scrolls vertically. Set --evo-grid-max on
   the wrap when the page above the grid is taller or shorter.
   <div class="evo-gridwrap"><table class="table table-sm table-hover mb-0 evo-grid">
   thead / tbody / tfoot (the total)</table></div> */
.evo-gridwrap { max-height: var(--evo-grid-max, max(320px, calc(100vh - 290px))); overflow: auto; border: 1px solid #dee2e6; border-radius: .375rem; }
table.evo-grid { font-size: .88rem; }
table.evo-grid th { white-space: nowrap; font-size: .72rem; text-transform: uppercase; color: #6c757d; font-weight: 600; background: #f8f9fa; vertical-align: middle; }
table.evo-grid thead th { position: sticky; top: 0; z-index: 3; box-shadow: inset 0 -1px 0 #dee2e6; border-bottom: 0; }
table.evo-grid tfoot td { position: sticky; bottom: 0; z-index: 3; background: #fff; box-shadow: inset 0 1px 0 #dee2e6; font-weight: 600; border-bottom: 0; }
table.evo-grid td { vertical-align: top; }
/* 5.5 long text: two lines and a pencil; the textarea stays in the row (hidden)
   so the x[] arrays stay aligned, and the pencil swaps it in. */
.evo-clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.evo-pencil { font-size: 1rem; color: #6c757d; cursor: pointer; }
.evo-pencil:hover { color: var(--bs-primary); }
/* A line that goes on save (5.7): struck through, controls left readable */
tr.evo-struck > td { text-decoration: line-through; color: #adb5bd; }
tr.evo-struck > td input, tr.evo-struck > td .statusPill, tr.evo-struck > td .flag { text-decoration: none; }

/* History in a tab pane: history.inc prints its own legacy heading and pins a
   min-height; the tab already names it and a short history should not leave a gap.
   <div class="evo-hist"> loadLogHistory(null, "min(60vh, 32rem)") </div> */
.evo-hist .jumbotron > .display-6, .evo-hist .jumbotron > hr { display: none; }
.evo-hist .jumbotron { padding: 0; margin: 0; background: transparent; }
.evo-hist #historyDiv { margin-top: 0 !important; }
.evo-hist .table-responsive { min-height: 0 !important; }

/* Forms in modals, additions (docs-dev/styling.inc 7.3, ruled 13-10-2026). The
   .evo-mform / .evo-msec family itself lives in style.css.
   Step number: a create form filled top to bottom (later sections depend on earlier
   ones) numbers its section headings in place of the icon. Grouped edit forms keep icons.
     <h6><span class="evo-msec-num">1</span>Customer</h6>
     <p class="evo-msec-hint is-num">…</p>     hint indented under the heading text
   Sub-panel: a grey inset inside a card for a block the JS reveals after a pick
   (New customer account, Site address, New contact, Pipeline). Its heading is
   optional, small and bold.
     <div class="evo-msub" style="display:none"><div class="evo-msub-h">New contact</div> fields </div> */
.evo-msec-num {
	display: inline-flex; align-items: center; justify-content: center; flex: none;
	width: 1.35rem; height: 1.35rem; border-radius: 50%;
	background: var(--main-highlight-color, var(--bs-primary)); color: #fff; font-size: .72rem; letter-spacing: 0;
}
.evo-msec-hint.is-num { padding-left: 2.7rem; }
.evo-msub { background: #f8f9fa; border: 1px solid #e9ecef; border-radius: .4rem; padding: .6rem .75rem .2rem; margin: .25rem 0 .6rem; }
.evo-msub-h { font-size: .82rem; font-weight: 600; color: #495057; margin-bottom: .4rem; }
/* Footer buttons sit right whether or not there is a note (the note's margin-right:auto
   still pushes it left). Cancel sits before the primary, default size (Q1, 13-10-2026). */
.evo-mform-foot { justify-content: flex-end; }
/* Sticky offset follows whichever box scrolls. style.css's bottom:-1rem suits a scrolling
   .modal-body (scrollable or fullscreen dialog: the foot covers the body's bottom padding).
   In a plain dialog the whole .modal scrolls, and -1rem left the foot half off screen
   (#addOpModal, a newModal largeModal), so it sits flush at 0 there. */
.modal .evo-mform-foot { bottom: 0; }
/* the default modal (.modal-md-fluid, global.js) scrolls its body too (13-10-2026: a 13px strip
   of content showed under the foot in #jobAddressModal), and so does extraLargeModal
   (.modal-xl-fluid, 21-10-2026: #returnGoodsModal) */
.modal-dialog-scrollable .evo-mform-foot, .modal-fullscreen .evo-mform-foot,
.modal-md-fluid .evo-mform-foot, .modal-xl-fluid .evo-mform-foot { bottom: -1rem; }
@media (max-width: 575.98px) { .modal-fullscreen-sm-down .evo-mform-foot { bottom: -1rem; } }
@media (max-width: 767.98px) { .modal-fullscreen-md-down .evo-mform-foot { bottom: -1rem; } }
@media (max-width: 991.98px) { .modal-fullscreen-lg-down .evo-mform-foot { bottom: -1rem; } }
@media (max-width: 1199.98px) { .modal-fullscreen-xl-down .evo-mform-foot { bottom: -1rem; } }
@media (max-width: 1399.98px) { .modal-fullscreen-xxl-down .evo-mform-foot { bottom: -1rem; } }
/* A two-way choice at the top of a form (Close: Won / Lost): btn-check radios, equal widths */
.evo-choice { display: flex; gap: .5rem; }
.evo-choice > .btn { flex: 1 1 0; }
/* Full-page create form (styling.inc 7.3.3 amendment, 13-10-2026; first page: jobadd).
   The modal form on a page of its own: numbered cards in one column, capped at a
   readable width, and the foot pinned to the bottom of the window like .evo-actionbar
   rather than to a modal body (no negative margins, its own border and shadow).
     <div class="evo-mform evo-page-form"><form …> cards … <div class="evo-mform-foot">…</div></form></div> */
.evo-page-form { max-width: 60rem; }
.evo-page-form .evo-mform-foot .btn { white-space: nowrap; }
.evo-page-form .evo-mform-foot {
	bottom: 8px; margin: 0; background: #fff;
	border: 1px solid #dee2e6; border-radius: .5rem; box-shadow: 0 -2px 12px rgba(0,0,0,.15);
}
/* Summary panel (styling.inc #pageform1310 amendment, 13-10-2026). The form and a summary
   beside it, centred together. The summary holds one row per card (number, name, what was
   entered, "Required" when it is missing, warning flags), any totals, then Cancel and the
   primary (form="…" so it posts the form). From 1200px wide the summary shows and stays in
   view, and the pinned foot is hidden; narrower, it is hidden and the form is centred with
   its foot as before.
     <div class="evo-page-split">
       <div class="evo-mform evo-page-form"><form id="form">… foot</form></div>
       <aside class="evo-page-aside"><div class="evo-sum">
         <div class="evo-sum-h">Summary</div>
         <a class="evo-sum-row" href="#card"><span class="evo-msec-num">1</span>
           <span class="evo-sum-body"><span class="evo-sum-k">Customer</span>
             <span class="evo-sum-v">…</span><span class="evo-sum-sub">…</span></span></a>
         <div class="evo-sum-total"><span>Total</span><span>…</span></div>
         <div class="evo-sum-foot"><span class="evo-mform-note">…</span>
           <div class="evo-sum-btns">Cancel, primary</div></div>
       </div></aside>
     </div>
   .evo-sum-v.is-missing = a required value not given yet; .is-empty = optional, not given. */
.evo-page-split { display: flex; gap: 1.25rem; align-items: flex-start; justify-content: center; }
.evo-page-split > .evo-page-form { flex: 1 1 auto; min-width: 0; }
.evo-page-aside { display: none; }
@media (min-width: 1200px) {
	.evo-page-aside {
		display: block; flex: 0 0 22rem; min-width: 0;
		position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto;
	}
	.evo-page-split .evo-page-form .evo-mform-foot { display: none; }
}
.evo-sum { background: #fff; border: 1px solid #dee2e6; border-radius: .5rem; box-shadow: 0 2px 10px rgba(0,0,0,.06); }
.evo-sum-h { padding: .6rem 1rem; font-weight: 600; border-bottom: 1px solid #e9ecef; }
.evo-sum-row { display: flex; align-items: flex-start; gap: .65rem; padding: .55rem 1rem;
	color: inherit; text-decoration: none; border-bottom: 1px solid #f1f3f5; }
.evo-sum-row:hover, .evo-sum-row:focus-visible { background: #f8f9fa; color: inherit; }
.evo-sum-row > .evo-msec-num { margin-top: .1rem; }
.evo-sum-body { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; gap: .05rem; }
.evo-sum-k { font-size: .75rem; font-weight: 600; color: #6c757d; }
.evo-sum-v { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.evo-sum-v.is-missing { color: #dc3545; font-weight: 400; }
.evo-sum-v.is-empty { color: #6c757d; font-weight: 400; }
.evo-sum-sub { font-size: .82rem; color: #6c757d; overflow-wrap: anywhere; }
.evo-sum-sub:empty { display: none; }
.evo-sum-sub .flag { margin: .15rem .25rem 0 0; }
.evo-sum-line { display: flex; justify-content: space-between; gap: .5rem; font-size: .85rem; }
.evo-sum-line > :last-child, .evo-sum-total > :last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }
.evo-sum-total { display: flex; justify-content: space-between; gap: .5rem; padding: .6rem 1rem;
	font-weight: 700; background: #f8f9fa; border-bottom: 1px solid #e9ecef; }
.evo-sum-foot { padding: .75rem 1rem; }
.evo-sum-btns { display: flex; gap: .5rem; margin-top: .5rem; }
.evo-sum-btns > .btn { flex: 1 1 0; white-space: nowrap; }
/* Predefined tasks foot in form mode (tasktemplateslist.inc, in #taskTemplatesListModal).
   Moved from the include's own <style> block 13-10-2026. */
.ttl-foot { position: sticky; bottom: -1rem; z-index: 5; display: flex; align-items: center; gap: .9rem;
	background: #fff; border-top: 1px solid #dee2e6; margin: .75rem -1rem -1rem; padding: .65rem 1rem; }
.ttl-foot .btn { width: auto; }

/* Country pick list under a text input (opportunityadd, siteadd, siteedit, clientadd).
   Moved here from page <style> blocks 13-10-2026; those blocks also set a page-wide
   input[type="text"] { width:100%; padding:8px } that is deliberately NOT carried over.
     <div class="autocomplete-container"><input class="form-control countryInput">
       <div class="autocomplete-list"></div></div>     items: div.autocomplete-item */
.autocomplete-container { position: relative; width: 100%; }
.autocomplete-list {
	position: absolute; top: 100%; left: 0; right: 0; z-index: 10000;
	max-height: 200px; overflow-y: auto; background: #fff;
}
.autocomplete-list:not(:empty) { border: 1px solid #dee2e6; border-radius: .375rem; box-shadow: 0 .25rem .75rem rgba(0,0,0,.08); }
.autocomplete-item { padding: 8px; cursor: pointer; }
.autocomplete-item:hover { background-color: #f0f0f0; }

/* Address label: one clickable row standing in for an address and the fields behind it
   (first: Delivery Address on the project General tab, jobeditgen.inc, which opens
   #jobAddressModal). Icon, one or two lines that ellipsis, a source badge with an Unsaved
   chip stacked under it while the change waits for the page's Save, and an edit icon.
     <button type="button" class="evo-addr-label [is-empty] [is-unsaved]">
       <i class="material-symbols-rounded evo-addr-label-icon">location_on</i>
       <span class="evo-addr-label-lines"><span class="evo-addr-label-l1"></span><span class="evo-addr-label-l2"></span></span>
       <span class="evo-addr-label-tags"><span class="evo-addr-label-badge is-site|is-own|is-oneoff">Site</span>
         <span class="evo-addr-label-unsaved">Unsaved</span></span>
       <i class="material-symbols-rounded evo-addr-label-edit">edit</i></button> */
.evo-addr-label {
	display: flex; align-items: center; gap: .6rem; width: 100%; min-height: calc(1.5em + .75rem + 2px);
	padding: .4rem .65rem; text-align: left; color: #212529; background: #fff;
	border: 1px solid #dee2e6; border-radius: .375rem; cursor: pointer;
	transition: border-color .15s, box-shadow .15s;
}
.evo-addr-label:hover { border-color: var(--bs-primary); }
.evo-addr-label:focus-visible { outline: 0; border-color: var(--bs-primary); box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .2); }
.evo-addr-label-icon { flex: 0 0 auto; font-size: 1.35rem; color: var(--bs-primary); }
.evo-addr-label-lines { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.evo-addr-label-l1, .evo-addr-label-l2 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.evo-addr-label-l2 { font-size: .85em; color: #6c757d; }
.evo-addr-label-l2:empty { display: none; }
.evo-addr-label.is-empty .evo-addr-label-l1 { color: #6c757d; font-style: italic; }
.evo-addr-label.is-empty .evo-addr-label-icon { color: #adb5bd; }
.evo-addr-label-tags { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: .15rem; }
.evo-addr-label-badge, .evo-addr-label-unsaved {
	padding: .1rem .45rem; line-height: 1.3; border-radius: 1rem; font-size: .72rem; font-weight: 600; white-space: nowrap;
}
.evo-addr-label-badge { background: #e9ecef; color: #495057; }
.evo-addr-label-badge.is-site { background: #e7f1ff; color: #0a58ca; }
.evo-addr-label-badge.is-oneoff { background: #fff3cd; color: #855d00; }
.evo-addr-label-unsaved { display: none; background: #fde2e1; color: #b02a37; }
.evo-addr-label.is-unsaved .evo-addr-label-unsaved { display: inline-block; }
.evo-addr-label-edit { flex: 0 0 auto; font-size: 1.1rem; color: #adb5bd; }
.evo-addr-label:hover .evo-addr-label-edit { color: var(--bs-primary); }
/* A read-only address block with its line breaks kept (the modal's site card) */
.evo-addr-text { white-space: pre-line; }
/* Read-only text shown back in a form or modal (styling.inc 7.3.4): what was entered
   earlier, line breaks kept, scrolls past ~8 lines. First use: a defect's required
   rectification and "What was done" in its move modals and Rectification panel. */
.evo-readout { white-space: pre-line; overflow-wrap: anywhere; max-height: 12rem; overflow: auto;
	background: var(--bs-tertiary-bg, #f8f9fa); border: 1px solid var(--bs-border-color, #dee2e6);
	border-radius: var(--bs-border-radius, .375rem); padding: .4rem .6rem; font-size: .875rem; }

/* Pickers in modal forms (13-10-2026, Shane). A selectFilter list inside a §7.3
   modal form (.evo-mform) opens IN THE FLOW at its default 300px instead of
   floating: the modal grows to fit it (up to the window) and the body scrolls,
   so a long list can always be browsed. evoModal.js scrolls it into view.
   Raised above the sticky .evo-mform-foot (z-index 5). */
.evo-mform div.filtered_list > select.filtered_list {
	position: relative;
	top: 0;
	float: none;
	margin-top: 4px;
	border-radius: .4rem;
	box-shadow: 0 4px 12px rgba(0, 0, 0, .12);
}

/* Row states on a working grid (docs-dev/styling.inc 1.8 / 5.7): a light tint and
   a 4px left edge on the first cell. evo-row-flag = the system flagged the row
   (amber); evo-row-done = the user entered or saved something (green, and it wins
   when both apply). The edge is an inset shadow so the columns do not shift.
   <tr class="evo-row-flag"> / <tr class="evo-row-flag evo-row-done"> (invminmax) */
table > tbody > tr.evo-row-flag > td { background: rgba(255,193,7,.12); }
table > tbody > tr.evo-row-flag > td:first-child { box-shadow: inset 4px 0 0 #ffc107; }
table > tbody > tr.evo-row-done > td { background: rgba(25,135,84,.08); }
table > tbody > tr.evo-row-done > td:first-child { box-shadow: inset 4px 0 0 #198754; }

/* Web addresses linked in ticket chat and descriptions (ticketMessageHtml() in
   functions.php, 15-10-2026). A long address breaks anywhere rather than
   stretching the bubble or the page. */
a.evo-msg-link { overflow-wrap: anywhere; word-break: break-word; }

/* Page presence (EvoSession::presenceBadges, library/session.php): named badges of the
   other staff who have the same record open, kept current by evoPresence in global.js.
   Sits in the page header. A coloured dot per person (.evo-presence-c0..5, from their
   user id) so the same person reads the same on every screen; .is-idle = their tab is
   in the background, so they are there but probably not looking.
     <span class="evo-presence" id="evoPresence"><span class="evo-presence-badge evo-presence-c2">Mark</span></span> */
.evo-presence { display: inline-flex; flex-wrap: wrap; align-items: center; gap: .3rem; margin-right: .5rem; vertical-align: middle; }
.evo-presence[hidden] { display: none; }
.evo-presence::before { content: "visibility"; font-family: "Material Symbols Rounded"; font-size: 1.15rem; line-height: 1; color: #6c757d; }
.evo-presence-badge {
	display: inline-flex;
	align-items: center;
	gap: .3rem;
	border: 1px solid #ced4da;
	background: #fff;
	color: #212529;
	border-radius: 1rem;
	padding: .05rem .6rem .05rem .45rem;
	font-size: .85rem;
	line-height: 1.4;
	white-space: nowrap;
	cursor: default;
}
.evo-presence-badge::before { content: ""; width: .55rem; height: .55rem; border-radius: 50%; background: currentColor; }
.evo-presence-c0::before { background: #0d6efd; }
.evo-presence-c1::before { background: #198754; }
.evo-presence-c2::before { background: #d63384; }
.evo-presence-c3::before { background: #fd7e14; }
.evo-presence-c4::before { background: #6f42c1; }
.evo-presence-c5::before { background: #20c997; }
.evo-presence-badge.is-idle { opacity: .55; border-style: dashed; }

/* XERO PILL - the one record action that opens a record's Xero integration
   panel (credit notes first). Xero's own blue so it reads as "Xero" at a glance;
   pill-shaped and sized to sit in a row of btn-sm band actions. */
.btn.evo-xero-pill,
.btn.evo-xero-pill:hover,
.btn.evo-xero-pill:focus,
.btn.evo-xero-pill:active {
	background: #13B5EA;
	color: #fff;
	font-weight: 600;
	border: 0;
	border-radius: 20px;
	padding: .25rem 1.1rem;
}
.btn.evo-xero-pill:hover { background: #0f9fcf; }
