/* CRM application styles — follows Intricate Solutions CSS conventions */

/* ── Sidebar ──────────────────────────────────────────────────────────── */
.sidebar-new {
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  width: 27rem;
  background: var(--primary);
  color: #fff;
  display: flex;
  flex-direction: column;
  z-index: 10;
  transition: width 0.3s ease;
  overflow: hidden;
}
.sidebar-new.collapsed {
  width: 5.66rem;
}
.sidebar-new.collapsed .sidebar-label,
.sidebar-new.collapsed .sidebar-section-label {
  display: none;
}
.sidebar-toggle-row {
  display: flex;
  align-items: center;
  height: 4.5rem;
  padding: 0 var(--size-5);
  border-bottom: 1px solid rgba(255,255,255,0.15);
}
/* Descendant selector, not a bare class: controls.css's .button.transparent
   (specificity 0,2,0) sets color to var(--primary) -- the exact colour of the
   sidebar's own background -- and beat the plain .sidebar-toggle-btn (0,1,0),
   rendering the hamburger invisible against the sidebar. There was no visible
   control to click, which is why the sidebar never appeared to expand. */
.sidebar-new .sidebar-toggle-btn {
  color: #fff;
  font-size: 1.5rem;
  cursor: pointer;
}
.sidebar-new .sidebar-toggle-btn:hover { color: #FFDB9F; }
/* overflow-x is pinned to hidden because a non-visible overflow-y computes the
   other axis from visible to auto, so overflow-y alone produced a second,
   horizontal scrollbar under the nav. The nav still scrolls when it is taller
   than the sidebar; the bar itself is hidden in every engine. */
.sidebar-nav-list {
  list-style: none;
  padding: 0;
  margin: 0;
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.sidebar-nav-list::-webkit-scrollbar { width: 0; height: 0; }
/* The <li> is a bare container: the padding, the hover background and the
   active border all live on the <a>, which stretches across the full row. When
   both carried the padding the <a> was only a content-width flex item, so the
   link ended at the label text and the rest of the row -- the <li>'s own
   padding -- highlighted on hover but was not clickable. The footer's Sign out
   is an <a class="sidebar-nav-item"> with no wrapper, so it is matched
   directly; a.sidebar-nav-item (0,1,1) also outranks the container rule. */
.sidebar-nav-item {
  display: block;
  padding: 0;
}
.sidebar-nav-item > a,
a.sidebar-nav-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: #fff;
  text-decoration: none;
  font-size: 0.95rem;
  transition: background 0.2s, color 0.2s;
  cursor: pointer;
  border-left: 3px solid transparent;
}
/* Row metrics are unchanged from before the <li> was emptied out: the <li> and
   the <a> each contributed 0.75rem/var(--size-6) then, so the anchor carries
   the sum now that it is the only padded box. The footer's Sign out never had
   a wrapper <li>, so it keeps the single set and its own height. */
.sidebar-nav-item > a {
  padding: 1.5rem calc(var(--size-6) * 2);
}
a.sidebar-nav-item {
  padding: 0.75rem var(--size-6);
}
.sidebar-nav-item > a:hover,
a.sidebar-nav-item:hover {
  background: rgba(255,255,255,0.12);
  color: #FFDB9F;
}
.sidebar-nav-item.active > a,
a.sidebar-nav-item.active {
  border-left-color: #FFDB9F;
  background: rgba(255,255,255,0.15);
  color: #FFDB9F;
}
.sidebar-nav-item i { font-size: 1.1rem; min-width: 1.2rem; text-align: center; }
.sidebar-section-label {
  padding: 0.75rem var(--size-6) 0.25rem;
  font-size: 0.92rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(255,255,255,0.5);
}
.sidebar-footer {
  border-top: 1px solid rgba(255,255,255,0.15);
  padding: var(--size-4) 0;
}

/* Wrapper shifts with sidebar. .content is nested inside .wrapper (see
   base.html), so it inherits this shift already -- it must NOT also carry
   its own margin-left, or the offset gets applied twice. */
.wrapper.sidebar-collapsed { margin-left: 5.66rem; transition: margin-left 0.3s; }
.wrapper.sidebar-expanded  { margin-left: 27rem;   transition: margin-left 0.3s; }

/* ── Header overrides ─────────────────────────────────────────────────── */
.new-ui-topheader {
  background: #878a91;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 4.5rem;
  padding: 0 var(--size-6);
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9;
  width: 100%;
  box-sizing: border-box;
}
.new-ui-topheader.sidebar-collapsed { padding-left: 5.66rem; transition: padding-left 0.3s; }
.new-ui-topheader.sidebar-expanded  { padding-left: 27rem;   transition: padding-left 0.3s; }
.new-logo { height: 2.5rem; }
#new-toprightnav { display: flex; align-items: center; gap: var(--size-5); }
.header-user-name { color: #fff; font-size: 0.92rem; }
.header-dialog-button { border:none; background:none; font-size:2rem; color:#EFEFEF; transition:color 0.3s; cursor:pointer; }
.header-dialog-button:hover { color:#fff; }
.header-icon-background { opacity: 0; color: #ACAEB3; transition: opacity 0.3s; }
.header-dialog-button:hover .header-icon-background { opacity: 1; }
.header-icon { color: #EFEFEF; }

/* Breadcrumb */
div.breadcrumb {
  background: #eee;
  font-style: italic;
  font-size: 1rem;
  color: #7F7F7F;
  height: 2.8rem;
  border-bottom: 0.075rem solid #ccc;
  display: flex;
  align-items: center;
  position: fixed;
  top: 4.5rem;
  left: 0;
  right: 0;
  z-index: 8;
}
/* Matches .new-ui-topheader's own sidebar-state padding -- without this the
   breadcrumb text sits at the collapsed-width offset even when the sidebar
   is expanded, rendering underneath it (sidebar has a higher z-index). */
div.breadcrumb.sidebar-collapsed { padding-left: 5.66rem; transition: padding-left 0.3s; }
div.breadcrumb.sidebar-expanded  { padding-left: 27rem;   transition: padding-left 0.3s; }
div.breadcrumb a { color: var(--primary); }

/* Content area — wrapper's margin-top already clears header + breadcrumb */
/* HOW TALL THE FIXED APP CHROME IS. The header is 4.5rem and the breadcrumb
   sits below it at top:4.5rem with height 2.8rem, so together they cover the
   first 7.3rem of the window and nothing scrolls out from under them. Anything
   pinning itself to the top of the viewport has to start BELOW that -- see
   .deal-sticky-header, which spent a release stuck behind them. */
:root { --chrome-height: 7.3rem; }

.content {
  padding-top: var(--size-6);
  min-height: calc(100vh - var(--chrome-height));
  /* min-height sizes the content box by default, so the padding stacked on top
     of it and pushed the page 1rem past the viewport -- a permanent vertical
     scrollbar on every page, even an empty one. */
  box-sizing: border-box;
}

/* Alert overlays */
.alert-overlay {
  position: fixed;
  bottom: var(--size-6);
  left: 50%;
  transform: translateX(-50%);
  z-index: 100;
  padding: var(--size-5) var(--size-7);
  border-radius: 0.4rem;
  box-shadow: var(--shadow);
  background: #eee;
  max-width: 36rem;
  width: 90%;
}
.alert-overlay.error { background: #fee; color: #f44; }
.alert-overlay.warning { background: #878a91; color: #fff400; }
.alert-overlay-inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

/* ── Stage & type badges ──────────────────────────────────────────────── */
.stage-badge {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 0.25rem;
  font-size: 0.92rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.stage-identified   { background: #e8f4f8; color: var(--primary); }
.stage-qualified    { background: #d6eaf8; color: #1a6b9a; }
.stage-scoping      { background: #eaf6f0; color: #1f7a5c; }
.stage-proposed     { background: #fef9e7; color: #b7950b; }
.stage-negotiation  { background: #fdf2e9; color: var(--secondary); }
.stage-won          { background: #eafaf1; color: #1e8449; }
.stage-lost         { background: #f4f4f4; color: var(--accent); }

/* Stale-opportunity indicator (no stage change/activity in 30+ days) */
.stale-badge {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.1rem 0.4rem;
  border-radius: 0.25rem;
  font-size: 0.92rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  background: #fdecea;
  color: #b3261e;
}

.deal-type-badge {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 0.25rem;
  font-size: 0.92rem;
  font-weight: bold;
}
.deal-type-badge.new_business        { background: #eafaf1; color: #1e8449; }
.deal-type-badge.recurring_contract  { background: #fdf2e9; color: var(--secondary); }

/* WHERE THE DEAL HAS GOT TO. Same shape as .deal-type-badge, which it took
   the place of on the card, so the footer's rhythm is unchanged.

   COLOURED BY WHO IS HOLDING IT rather than one colour per label. Fifteen
   labels in fifteen colours is a legend to memorise; four families -- ours to
   do, in progress, with the client, closed -- can be read down a column of
   eighty cards without one. The label itself carries the detail. */
.deal-stage-badge {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 0.25rem;
  font-size: 0.92rem;
  font-weight: bold;
  white-space: nowrap;
}
/* Waiting on us to do something with it. */
.deal-stage-badge.stage-early   { background: #fdf2e9; color: var(--secondary); }
/* Moving: being scoped, with the technical team, being quoted. */
.deal-stage-badge.stage-working { background: #eaf2fa; color: #1f618d; }
/* Ours to send -- the one state where the next move is a person here. */
.deal-stage-badge.stage-ours    { background: #fef5e7; color: #9c640c; }
/* With the client; the next move is theirs. */
.deal-stage-badge.stage-client  { background: #eafaf1; color: #1e8449; }
/* Done, either way. Deliberately quiet: a closed deal on the board is
   context, not work. */
.deal-stage-badge.stage-closed  { background: #f2f3f4; color: #566573; }

.deal-badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 0.2rem;
  font-size: 0.92rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.deal-badge.renewal { background: var(--secondary); color: #fff; }
/* Incomplete is a state of the RECORD, not of the deal, so it is deliberately
   quieter than At Risk -- a half-entered deal needs finishing, a large deal
   going quiet needs someone on the phone, and the board should not shout the
   same volume at both. */
.deal-badge.incomplete { background: #f1f2f3; color: #5a5c60; border: 1px solid var(--accent-faded); }
.deal-badge.at-risk    { background: #fdecea; color: #b3261e; }

.role-badge { display:inline-block; padding:0.15rem 0.5rem; border-radius:0.25rem; font-size:0.92rem; font-weight:bold; }
.role-admin            { background:#fdf2e9; color:var(--secondary); }
.role-sales_rep        { background:#eafaf1; color:#1e8449; }
.role-ops_management   { background:#e8f4f8; color:var(--primary); }

.renewal-row td { background:#fff9f0 !important; }

/* ── Searchable select (type-ahead combobox) ──────────────────────────── */
/* .text-input-container is display:flex with its (former) <select> as the
   sole flex item stretching via .text-input's flex:1. The plugin swaps that
   select for a <span class="searchable-select-wrap"><input></span> -- the
   wrap, not the input, is now the direct flex child, so it also needs flex:1
   (and to itself be a flex container) or the input inside falls back to a
   native, un-stretched width instead of filling the field like its siblings. */
.text-input-container .searchable-select-wrap { position:relative; display:flex !important; flex:1 !important; min-width:0; }
.searchable-select-wrap { position:relative; display:block; }
.text-input-container .searchable-select-wrap .searchable-select-input {
  flex:1 !important; width:100% !important; min-width:0; box-sizing:border-box;
}
/* visibility, not opacity alone: the read-only view's `.ro-fieldset
   select:disabled { opacity:1 }` (deals/detail.html) is the more specific rule
   and was winning, which put the native select's dropdown arrow back on screen
   -- a zero-width control painting its chevron over the first letter of the
   name beside it. visibility:hidden cannot be undone that way, and a hidden
   select is still submitted with the form. */
.searchable-select-hidden {
  position:absolute; opacity:0; visibility:hidden;
  height:0; width:0; pointer-events:none;
}
.searchable-select-error .searchable-select-input { border-color:#f00; }
.searchable-select-list {
  display:none; position:absolute; top:100%; left:0; right:0; z-index:50;
  background:#fff; border:1px solid var(--accent-faded); border-radius:0.3rem;
  max-height:14rem; overflow-y:auto; box-shadow:0 2px 8px rgba(0,0,0,0.12); margin-top:2px;
}
.searchable-select-item { padding:0.4rem 0.6rem; cursor:pointer; font-size:0.92rem; }
.searchable-select-item:hover, .searchable-select-item.active { background:#f0f4f8; }
.searchable-select-empty { padding:0.4rem 0.6rem; font-size:0.92rem; color:var(--accent); }

/* ── Locked (computed, read-only) fields ──────────────────────────────── */
/* The base-case's global `input:disabled { opacity: 0.1; }` (css/new-style.css)
   is meant for genuinely inert fields, but a calculated value (Confidence to
   Close, Expected Value, Value) still needs to be legible -- readonly instead
   of disabled sidesteps that rule entirely (still non-editable, still not
   focusable-and-typeable) and this class adds a visible "computed" tint. */
.text-input-locked {
  background-color: #eef1f4 !important;
  color: #333 !important;
  opacity: 1 !important;
  cursor: default;
}

/* ── Form section containers ──────────────────────────────────────────── */
/* Visually separates each portion of the deal form (Overview, Value & Line
   Items, BANT, etc.) so fields don't read as one undifferentiated block.
   Works on a plain <div> or directly on a <details> (its <summary> just
   renders as a normal first child inside the same padding). */
.form-section-box {
  /* A heavier box than the hairline it used to be. This form is long and made
     almost entirely of labelled inputs, so a 1px grey line was not enough to
     tell one group of fields from the next -- the whole thing read as one
     undifferentiated wall. A 2px edge, a teal cap and real space between boxes
     make each section something you can see the shape of before reading it. */
  border: 2px solid var(--accent-faded);
  border-top: 4px solid var(--primary);
  border-radius: 0.5rem;
  padding: var(--size-7);
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.07);
}
/* Sections after the first are spaced by their own margin rather than by an
   inline style repeated on each one in the template. */
.form-section-box + .form-section-box,
.form-section-box { margin-bottom: var(--size-7); }

/* Section headings, in one place instead of per-section inline styles. */
.form-section-box > h4,
.form-section-box > summary {
  font-size: 1.15rem;
  font-weight: bold;
  color: var(--primary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0 0 var(--size-6);
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--accent-faded);
}
.form-section-box > summary { cursor: pointer; }
.form-section-box:not([open]) > summary { margin-bottom: 0; border-bottom: 0; }

/* ── Status messages ──────────────────────────────────────────────────── */
.error_message   { color:#f00; background:#fee; border:1px solid #fcc; }
.success_message { color:#0a0; background:#efe; border:1px solid #cfc; }
.in_progress_message { color:#880; background:#ffe; border:1px solid #cc0; }


/* ── Overlay scrollbars, everywhere ───────────────────────────────────── */
/* The To-Do matrix proved the pattern out on its four quadrants; this is the
   same thing for every scrolling box in the app, including the page itself.
   At rest the thumb is transparent, so a box with more in it than fits still
   looks like a clean box. It fades in while you scroll or hover and fades out
   again shortly after scrolling stops -- see crm.js, which adds .is-scrolling,
   since CSS has :hover but no "is being scrolled".

   This deliberately overrides the base case's 16px teal bars with arrow
   buttons (css/new-style.css, "custom scrollbar"). crm.css is the last
   stylesheet in base.html, so these win at equal specificity.

   The track still takes its space -- these are styled classic scrollbars, not
   true overlay ones -- so nothing shifts sideways when the thumb appears. */
* {
  scrollbar-width: thin;                          /* Firefox */
  scrollbar-color: transparent transparent;
  transition: scrollbar-color 0.25s ease;
}
*:hover,
.is-scrolling {
  scrollbar-color: rgba(0,0,0,0.22) transparent;
}

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; border: 0; }
::-webkit-scrollbar-corner { background: transparent; }
/* The base case draws gradient arrow buttons at both ends. At 8px they are
   noise, and they cannot be transparent-at-rest the way the thumb is. */
::-webkit-scrollbar-button { display: none; width: 0; height: 0; border: 0; }
::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: 4px;
  border: 0;
  background-clip: padding-box;
  transition: background 0.25s ease;
}
:hover::-webkit-scrollbar-thumb,
.is-scrolling::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.22); }
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.38); }

/* ──────────────────────────────────────────────────────────────────────────
   The deal form's field guide, and the incomplete-save dialog.

   COLOUR IS NEVER THE ONLY SIGNAL. Each state carries a left border weight and
   a background tint as well as a hue, and the legend names every state in
   words. Red/green alone excludes the ~8% of men with a colour vision
   deficiency, and this form is mostly read by a sales team, not by everyone.

   The hues are the palette's own (CSS.md) wherever it has one: --secondary is
   the app's warning colour and does the work of "red" so the form does not
   introduce a second alarm colour. Green and amber are not in the palette --
   there is no "success" or "caution" token -- so they are defined here, once,
   at contrast ratios that clear WCAG AA against white.
   ────────────────────────────────────────────────────────────────────────── */
:root {
  --wizard-green: #1B7A4B;
  --wizard-green-bg: #EEF7F1;
  --wizard-yellow: #8A6100;
  --wizard-yellow-bg: #FDF6E7;
  --wizard-red: var(--secondary);
  --wizard-red-bg: #FBEFE9;
  --wizard-grey: var(--accent);
  --wizard-grey-bg: #F6F6F7;
}

.wizard-bar {
  display: flex;
  align-items: center;
  gap: var(--size-6);
  flex-wrap: wrap;
  margin-bottom: var(--size-6);
}
.wizard-toggle { display: inline-flex; align-items: center; gap: 0.4rem; }
.wizard-bar.on .wizard-toggle {
  background-color: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.wizard-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--size-6);
  font-size: 0.92rem;
}
.wizard-key {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  white-space: nowrap;
  font-weight: bold;
  padding: 0.15rem 0.5rem;
  border-radius: 0.3rem;
  border-left: 0.4rem solid currentColor;
  background: #fff;
}
.wizard-key.green  { color: var(--wizard-green); }
.wizard-key.yellow { color: var(--wizard-yellow); }
.wizard-key.red    { color: var(--wizard-red); }
.wizard-key.grey   { color: var(--wizard-grey); }

/* Applied to the control's own container, so the spotlight sits on the input
   rather than on a wrapper that might hold two of them.
   
   DELIBERATELY LOUD. The first version was a thin left bar and a pale tint,
   which disappeared against a form of this size -- a guide you have to hunt for
   is not guiding. This is a full ring in the state's colour, a thick left bar
   and a tinted field, so the state of a field is readable from across the form
   without reading the field. The left bar and the ring are both non-colour
   signals (weight and shape), so the four states stay distinguishable without
   relying on hue alone. */
[data-wizard-state] {
  border: 2px solid transparent;
  border-left-width: 0.5rem;
  padding: 0.15rem 0.3rem;
  border-radius: 0.3rem;
  transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}
.wizard-green {
  border-color: var(--wizard-green);
  background-color: var(--wizard-green-bg);
  box-shadow: 0 0 0 2px rgba(27,122,75,0.16);
}
.wizard-yellow {
  border-color: var(--wizard-yellow);
  background-color: var(--wizard-yellow-bg);
  box-shadow: 0 0 0 2px rgba(138,97,0,0.18);
}
.wizard-red {
  border-color: var(--wizard-red);
  background-color: var(--wizard-red-bg);
  box-shadow: 0 0 0 2px rgba(189,75,0,0.20);
}
/* Grey is the one state that must NOT shout: it means "nothing needed from you
   here". It gets the same shape so the row still lines up, in a colour that
   recedes. */
.wizard-grey {
  border-color: var(--accent-faded);
  border-left-color: var(--wizard-grey);
  background-color: var(--wizard-grey-bg);
}

/* The label above a spotlit field picks up the state's colour too, so the eye
   lands on the field NAME rather than on an anonymous coloured box. */
[data-wizard-field].wizard-red > label,
[data-wizard-state].wizard-red + label { color: var(--wizard-red); }

/* A section containing anything red is marked on its own edge, so a collapsed
   or scrolled-past section still says it needs attention. */
.form-section-box:has([data-wizard-state="red"]) { border-color: var(--wizard-red); }
.form-section-box:has([data-wizard-state="yellow"]):not(:has([data-wizard-state="red"])) {
  border-color: var(--wizard-yellow);
}

/* Nobody asked for an animated form. Respect that. */
@media (prefers-reduced-motion: reduce) {
  [data-wizard-state] { transition: none; }
}

/* ── Confirmation dialog ──────────────────────────────────────────────────
   Mirrors the .qv-overlay/.qv-card Quick View modal, but named for what it is
   and defined ONCE here rather than copied inline into a template. (The qv-
   styles are currently duplicated in three templates; this does not fix that,
   but it does not add a fourth copy either.) */
.confirm-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: var(--size-7);
}
.confirm-overlay[hidden] { display: none; }
.confirm-card {
  background: #fff;
  border-radius: 0.4rem;
  box-shadow: var(--shadow);
  padding: var(--size-7);
  max-width: 34rem;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
}
.confirm-header {
  display: flex;
  align-items: flex-start;
  gap: var(--size-5);
  margin-bottom: var(--size-6);
}
.confirm-header h3 { margin: 0; font-size: 1.25rem; }
.confirm-icon { color: var(--secondary); font-size: 1.5rem; line-height: 1.4; }
.confirm-body { margin: 0 0 var(--size-5); }
.confirm-missing {
  margin: 0 0 var(--size-6);
  padding-left: var(--size-7);
  color: var(--wizard-red);
  font-weight: bold;
}
.confirm-missing li { margin-bottom: 0.2rem; }
.confirm-note {
  font-size: 0.92rem;
  color: var(--accent);
  background: var(--primary-faded);
  border-radius: 0.3rem;
  padding: var(--size-5);
  margin: 0;
}
.confirm-actions {
  display: flex;
  gap: var(--size-5);
  margin-top: var(--size-7);
  flex-wrap: wrap;
}

/* ──────────────────────────────────────────────────────────────────────────
   jQuery UI widgets keep the app's typeface.

   The base theme hard-sets Arial on .ui-widget and again on the controls inside
   one, at a specificity the `html { font-family: Lato }` in new-style.css cannot
   reach. Every date picker, autocomplete dropdown and multiselect would
   otherwise render in a different face from the form around it -- which is
   exactly the kind of "off" that is hard to name when you are looking at it.

   This did not bite before only because the theme stylesheet was 404ing (its
   path was missing /dist/) and no jQuery UI CSS was loading at all. Restoring
   the theme restores the Arial rules with it, so the two changes belong
   together and neither is safe to make alone.
   ────────────────────────────────────────────────────────────────────────── */
.ui-widget,
.ui-widget input,
.ui-widget select,
.ui-widget textarea,
.ui-widget button {
  font-family: 'Lato', sans-serif;
}

/* ──────────────────────────────────────────────────────────────────────────
   Excel-style column filters (static/js/column-filter.js)

   The button lives in the table's filter row and stays the width of its column;
   the panel is fixed-position and appended to <body>, so it is sized here in
   absolute terms rather than relative to a parent it does not have.
   ────────────────────────────────────────────────────────────────────────── */
.col-filter { position: relative; }
.col-filter-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.3rem;
  width: 100%;
  padding: 0.2rem 0.4rem;
  font-size: 0.92rem;
  font-family: 'Lato', sans-serif;
  color: var(--dark);
  background: #fff;
  border: 1px solid var(--accent-faded);
  border-radius: 0.25rem;
  cursor: pointer;
  text-align: left;
}
.col-filter-btn:hover { border-color: var(--primary); }
.col-filter-btn.open { border-color: var(--primary); box-shadow: 0 0 0 2px var(--primary-faded); }
/* The label is the only part that may be squeezed; the funnel must stay put,
   or a long value pushes the affordance out of the button entirely. */
.col-filter-btn-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
  min-width: 0;
}
.col-filter-icon { flex: 0 0 auto; font-size: 0.8rem; color: var(--accent); }
/* A filtered column is legible at a glance across a wide table -- otherwise the
   only way to find out why rows are missing is to open each dropdown in turn. */
.col-filter.is-filtered .col-filter-btn {
  border-color: var(--primary);
  background: var(--primary-faded);
  font-weight: bold;
}
.col-filter.is-filtered .col-filter-icon { color: var(--primary); }

.col-filter-panel {
  z-index: 1200;
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid var(--accent-faded);
  border-radius: 0.3rem;
  box-shadow: 0 4px 14px rgba(0,0,0,0.18);
  overflow: hidden;
}
.col-filter-panel-head {
  padding: 0.4rem;
  border-bottom: 1px solid var(--accent-faded);
  flex: 0 0 auto;
}
.col-filter-search { width: 100%; font-size: 0.92rem; padding: 0.25rem 0.4rem; }
.col-filter-actions { display: flex; gap: 0.4rem; margin-top: 0.3rem; }
.col-filter-action { font-size: 0.85rem; padding: 0; min-width: 0; }
.col-filter-list { overflow-y: auto; flex: 1 1 auto; padding: 0.2rem 0; }
.col-filter-option {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.22rem 0.5rem;
  font-size: 0.92rem;
  font-weight: normal;
  cursor: pointer;
}
.col-filter-option:hover { background: var(--primary-faded); }
.col-filter-option span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.col-filter-option input { flex: 0 0 auto; margin: 0; }
.col-filter-empty { padding: 0.75rem 0.5rem; color: var(--accent); font-size: 0.92rem; text-align: center; }

/* ──────────────────────────────────────────────────────────────────────────
   Parked pages (templates/under_construction.html)

   Sizes are large in absolute terms because this app sets a 12px root: 8rem is
   96px of icon and 3rem is a 36px heading, which is what "big" has to mean
   here. Written in rem anyway so it still tracks if that root ever changes.

   The height is the viewport minus the header and breadcrumb strip, so the
   block sits in the middle of what is actually visible rather than in the
   middle of a page that does not fill the window.
   ────────────────────────────────────────────────────────────────────────── */
.under-construction {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--size-6);
  min-height: calc(100vh - 12rem);
  padding: var(--size-8) var(--size-7);
  color: var(--accent);
}
.under-construction-icon {
  font-size: 8rem;
  line-height: 1;
  color: var(--primary);
  opacity: 0.55;
}
.under-construction-title {
  margin: 0;
  font-size: 3rem;
  font-weight: bold;
  color: var(--primary);
}
.under-construction-note { margin: 0; font-size: 1.25rem; }

@media only screen and (max-width: 850px) {
  .under-construction-icon { font-size: 5.5rem; }
  .under-construction-title { font-size: 2.2rem; }
}

/* Create-an-opportunity action, shown in the Activities list's Deal column when
   the activity has no deal yet. Sized down to sit in a table row without
   stretching it. */
.activity-to-deal-btn {
  font-size: 0.85rem;
  padding: 0.15rem 0.5rem;
  white-space: nowrap;
}

/* Banner on the deal form when it was opened from an activity. */
.from-activity-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--size-6);
  background: var(--primary-faded);
  border: 1px solid var(--primary);
  border-left: 0.4rem solid var(--primary);
  border-radius: 0.4rem;
  padding: var(--size-6);
  margin-bottom: var(--size-6);
  font-size: 0.95rem;
}
.from-activity-banner > i { color: var(--primary); font-size: 1.4rem; line-height: 1.2; }
.from-activity-note { color: var(--accent); font-size: 0.92rem; }

/* ── Report a Bug dialog ──────────────────────────────────────────────────────
   THE DIALOG OPENED OFF-SCREEN. Three rules in new-style.css combined to put it
   there, and none of them is wrong on its own:

     .header-dialog               position:fixed; left:0; top:0; width:100%;
                                  height:100%; padding-top:7.5rem
     .fixed-width-header-dialog   width:40rem
     .header-dialog
       div.header-dialog-content  position:fixed; margin:auto auto 0.5rem

   The markup puts BOTH classes on the overlay element, so width:40rem won the
   cascade over width:100% and the full-screen backdrop became a 40rem column
   pinned to the left edge. The panel inside is position:fixed with no top/left/
   right/bottom set, which leaves a fixed element at its static position -- and
   margin:auto centres nothing when there are no offsets to resolve against. So
   the panel landed wherever that 7.5rem-padded 40rem column happened to put it,
   which on a shorter or more zoomed window is partly or entirely outside the
   viewport, with no way to scroll to it because the panel is fixed.

   Centring it properly: give the overlay its full-screen width back, then place
   the panel with real offsets rather than hoping margin:auto resolves. The caps
   keep it inside the viewport on a small screen and let a long form scroll
   inside itself instead of overflowing off the bottom.

   Overriding here rather than editing new-style.css: that sheet is the estate's
   shared structural CSS, crm.css loads after it (see base.html), and this is
   the only header-dialog in this app. */
.header-dialog.fixed-width-header-dialog {
  width: 100%;
  padding-top: 0;
}

.header-dialog
div.header-dialog-content {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  max-width: calc(100vw - 2rem);
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
}

/* The close X was position:fixed at top:10rem right:10rem -- pinned to the
   viewport corner rather than to the dialog it closes, so it drifted further
   from the panel the larger the window got. It belongs in the header bar it is
   already floated into, which needs a right padding to match the left one it
   already has, or the button sits flush against the panel edge. */
.header-dialog
div.header-dialog-content
div.header-dialog-header {
  padding-right: 0.90rem;
}

.header-dialog
div.header-dialog-content
div.header-dialog-header
span.close-dialog
.close-dialog-button {
  position: static;
  top: auto;
  right: auto;
}

/* ── Following a deal ─────────────────────────────────────────────────────
   The bell does two things -- it turns on notifications AND puts the deal in
   My Deals -- so the lit state has to be unmistakable rather than a subtle
   tint: somebody needs to be able to tell at a glance whether this deal is
   one of theirs. */
.follow-btn { display: inline-flex; align-items: center; gap: 0.4rem; }
.follow-btn.following {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.follow-btn.following:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.follow-count {
  display: inline-block;
  min-width: 1.2rem;
  padding: 0 0.3rem;
  border-radius: 0.6rem;
  background: rgba(0,0,0,0.15);
  font-size: 0.8rem;
  text-align: center;
}
/* On a pipeline card the bell is an icon alone -- there is no room for a word,
   and the card already says which deal it is. */
.deal-follow-btn { padding: 0 0.25rem; font-size: 0.8rem; color: var(--accent); }
.deal-follow-btn.following { color: var(--primary); }

/* A parked deal. Deliberately calm rather than alarming -- the whole point is
   that this one is fine and somebody said so, which a red badge would undercut. */
.deal-badge.paused { background: #eef1f4; color: #4a5568; border: 1px solid #cbd5e0; }
.paused-banner {
  display: flex; align-items: flex-start; gap: var(--size-6);
  background: #eef1f4; border: 1px solid #cbd5e0; border-left: 0.4rem solid #6B6C70;
  border-radius: 0.4rem; padding: var(--size-6); margin-bottom: var(--size-6);
  font-size: 0.95rem;
}
.paused-banner > i { font-size: 1.4rem; color: #4a5568; line-height: 1.2; }
.snooze-days-row { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.snooze-preset { padding: 0.2rem 0.6rem; font-size: 0.92rem; }
.snooze-preset.chosen { background: var(--primary); border-color: var(--primary); color: #fff; }

/* Which platform a synced meeting was on. Muted and small -- it sits beside the
   activity type, which is the primary classification; this is the detail
   underneath it, not a competing label. */
.platform-badge {
  display: inline-block; margin-left: 0.3rem; padding: 0.05rem 0.4rem;
  border-radius: 0.3rem; font-size: 0.75rem; white-space: nowrap;
  background: #eef1f4; color: #4a5568; border: 1px solid #cbd5e0;
}
.platform-badge.platform-in_person { background: #fff; color: var(--accent); }

/* ── Send to Quote: the three routes out of a deal ───────────────────────────
   A deal can go to a scoping app, straight to a blank quote, or straight to a
   quote off a template. The routing table only ever knew the first, so the
   other two had no way to be asked for.

   A menu rather than three buttons in the toolbar: they are one decision with
   three answers, and three peers would read as three unrelated actions -- and
   the row is already carrying five. */
.stq-menu {
  position: absolute;
  top: calc(100% + 0.3rem);
  right: 0;
  z-index: 40;
  min-width: 22rem;
  background: #fff;
  border: 1px solid var(--accent-faded);
  border-radius: 0.3rem;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.14);
  overflow: hidden;
}
.stq-option {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.6rem 0.8rem;
  background: none;
  border: 0;
  border-bottom: 1px solid #f2f2f2;
  cursor: pointer;
  font: inherit;
}
.stq-option:last-child { border-bottom: 0; }
.stq-option:hover:not(:disabled) { background: var(--accent-faded); }
/* Disabled while a send is in flight: this fans out tasks and can create draft
   projects in another app, and the tasks are not idempotent. */
.stq-option:disabled { opacity: 0.55; cursor: progress; }
/* Hand off is set apart because it answers a different question from the
   three above it: not "where does this deal go" but "who does it next".
   The rule rather than a gap, so it reads as a break and not as a bug. */
.stq-divider {
  height: 1px;
  margin: 0.25rem 0;
  background: var(--accent-faded);
}
.stq-title { display: block; font-weight: 600; }
/* What the route will DO, not just where it goes -- "no scoping work is
   created" is the part somebody needs before clicking, not after. */
.stq-note {
  display: block;
  font-size: 0.82rem;
  color: var(--accent);
  margin-top: 0.15rem;
}

/* ── Autosave status, deal edit form ──────────────────────────────────────
   Sits beside Save Deal and says what happened to the last field left. Muted
   at rest and while saving -- a rep should notice it only when it has
   something to say, and "Saving…" flickering in brand colour beside every
   field would be noise. The failure state is the loud one on purpose. */
.autosave-status {
  font-size: 0.85rem;
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  min-height: 1.2rem;
}
.autosave-status[data-state="saved"] { color: var(--primary); }
.autosave-status[data-state="error"] {
  color: var(--secondary);
  font-weight: bold;
}

/* Raised from a quote. Muted rather than coloured: it is provenance, not a
   warning, and a saturated glyph beside every such name would read as an alert
   the first hundred times somebody saw it. */
.deal-from-quote {
  color: var(--accent);
  font-size: 0.85em;
  opacity: 0.75;
  flex: 0 0 auto;
}


/* The deal name, frozen while the rest of the page scrolls.
   top IS NOT ZERO, and that is the whole of it. position:sticky pins to the
   nearest scrolling ancestor, which here is the window -- so top:0 pinned the
   name to the very top of the viewport, underneath the fixed header and
   breadcrumb, where it was perfectly stuck and completely invisible. It has to
   stop where the chrome ends.

   Declared here rather than inline on the element: an inline `top` wins over
   any stylesheet, so the next person to copy that style block would reproduce
   the same bug and it would look like CSS that simply does not work. */
.deal-sticky-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: var(--size-7);
  position: sticky;
  top: var(--chrome-height);
  z-index: 20;
  background: #fff;
  padding: var(--size-5) 0;
  box-shadow: 0 0.4rem 0.4rem -0.4rem rgba(0, 0, 0, 0.12);
}

/* THE DATE RANGE FILTER, shared by the Deals list and the Dashboard.

   One class rather than two copies because the two screens ask the same
   question with the same three controls, and a filter that looks like a
   different feature on each screen is read as one. The pipeline board has its
   own (.pipeline-filter-dates) because there the control has to sit inside an
   existing filter bar and share its wrapping rules; the visual result matches.

   The label is part of the control, not a heading: "Filter by date" in front of
   a dropdown that says "Expected Land" reads as a sentence, and without it a
   bare date type sitting above a table looks like a column header. */
.date-range-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: var(--size-6);
  padding: var(--size-5) var(--size-6);
  background: #f8f8f8;
  border: 1px solid var(--accent-faded);
  border-radius: 0.4rem;
}
.date-range-label {
  font-size: 0.92rem;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin: 0;
}
.date-range-filter select { min-width: 12rem; }
/* min-width:0 so the two date inputs can shrink rather than force the bar
   wider than the table it sits above. */
.date-range-filter input[type="date"] { min-width: 0; width: 9.5rem; }
.date-range-sep { font-size: 0.9rem; color: var(--accent); }
.date-range-summary {
  font-size: 0.92rem;
  color: var(--accent);
  /* Pushed to its own end of the bar: it is an answer, not another control,
     and sitting next to Apply it read as a third button's caption. */
  margin-left: auto;
}

/* ── Quotes linked to this deal ───────────────────────────────────────── */
/* Before this the only sign a deal was already quoted was a disabled button
   with a tooltip: no quote number, no status, no way to get to it. These sit
   beside the Send to Quote button because that is where somebody is standing
   when the question "is this already quoted?" occurs to them. */
.linked-quotes { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.linked-quote {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--accent-faded);
  border-radius: 1rem;
  background: #f3f6f9;
  font-size: 0.92rem;
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
}
.linked-quote:hover { background: var(--accent-faded); }
.linked-quote-number { font-weight: bold; }
/* The quoting app's own words (draft/sent/accepted), so the two screens agree
   without this one keeping a second vocabulary. */
.linked-quote-status { text-transform: uppercase; font-size: 0.78rem; opacity: 0.8; }
.linked-quote-total { opacity: 0.85; }

/* The quote's own words for the work, on the deal. A read-only block rather
   than a disabled textarea: it is 1,400 characters on average and nobody is
   editing it here, so it should read like prose rather than sit in a box
   pretending to be a field. */
.quoted-scope {
  white-space: pre-wrap;
  background: #eef1f4;
  border: 1px solid var(--accent-faded);
  border-radius: 0.3rem;
  padding: var(--size-5);
  font-size: 0.95rem;
  line-height: 1.45;
  max-height: 18rem;
  overflow-y: auto;
}
