/* ============================================================
   TitleKnight Design System — components.css
   All primitives (§ 9), composites (§ 10), data states (§ 13),
   form-validation reskin (§ 11.3), focus rings (§ 14.2),
   reduced-motion override (§ 5).
   ============================================================ */

/* -----------------------------------------------------------
   Base body — set once. Never override on a page.
   ----------------------------------------------------------- */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Reserve the window scrollbar's gutter at all times. Pages scroll on the
   document root (the shell has no inner overflow container), so a page that
   grows from short → tall (e.g. the order form swapping its loading skeleton
   for the full form, a grid paginating, a dialog opening) would otherwise pop
   the native scrollbar in/out — eating ~15px and shifting every centered
   .content block horizontally. `stable` keeps the gutter present even when no
   scrollbar is needed, so nothing shifts. Cleaner than `overflow-y: scroll`,
   which would paint an always-visible (greyed) track on short pages. */
html { scrollbar-gutter: stable; }
body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--ink-2);
  font-size: var(--fs-14);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* -----------------------------------------------------------
   Application shell (§ 8)
   ----------------------------------------------------------- */
.app    { display: grid; grid-template-columns: var(--layout-sidebar) 1fr; min-height: 100vh; }
.main   { display: flex; flex-direction: column; min-width: 0; }
.content {
  max-width: var(--layout-content-max);
  width: 100%;
  margin: 0 auto;
  padding: var(--layout-content-pad-y) var(--layout-content-pad-x) 40px;
}

/* Fluid modifier — opts a page out of the 1480px max-width centering so
   it spans the full width of the main column. Use for data-heavy pages
   that need every available pixel (EditClientOrder, dashboards with
   side-by-side panes, wide grids). Padding is preserved so content
   still has breathing room from the sidebar and viewport edge. */
.content.content--fluid { max-width: none; }

/* main-body is the wrapper around @@Body inside MainLayout. Migrated pages
   render <div class="content"> as their root; un-migrated (Radzen-styled)
   pages render their content directly. The :has() rule below leaves
   .content-wrapped pages alone (.content already pads itself) and applies
   sensible default container padding + max-width to everything else so the
   un-migrated pages don't span edge-to-edge. */
.main-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.main-body:not(:has(> .content)) {
  max-width: var(--layout-content-max);
  width: 100%;
  margin: 0 auto;
  padding: var(--layout-content-pad-y) var(--layout-content-pad-x) 40px;
}

/* Full-width banner that sits above .content (no max-width cap, no
   border-radius). Use for cross-context callouts like "creating order
   on behalf of {client}" — the banner stretches the entire main column
   so the message is unmissable. Inner padding matches layout content
   padding so the banner text aligns with the page-head text below it. */
.page-banner {
  width: 100%;
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px var(--layout-content-pad-x);
  font-size: var(--fs-135);
  border-bottom: 1px solid var(--line);
  background: #fff;
}
.page-banner i { flex: 0 0 auto; font-size: 16px; margin-top: 2px; }
.page-banner > .page-banner-body { flex: 1; min-width: 0; }
.page-banner .page-banner-title { font-weight: 700; }
.page-banner--info {
  background: var(--primary-50);
  color: var(--primary);
  border-bottom-color: rgba(1,30,92,.15);
}

.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  margin-bottom: 22px; gap: 16px; flex-wrap: wrap;
}
.page-title {
  font-size: var(--fs-24); font-weight: 700; color: var(--ink);
  letter-spacing: var(--tracking-title); margin: 0 0 4px;
}
.page-sub { color: var(--muted); font-size: var(--fs-14); margin: 0; }
.head-actions { display: flex; gap: 8px; align-items: center; }

/* -----------------------------------------------------------
   Sidebar (§ 8.4)
   ----------------------------------------------------------- */
.sidebar {
  background: var(--card); border-right: 1px solid var(--line);
  padding: 18px 14px; display: flex; flex-direction: column; gap: 4px;
  position: sticky; top: 0;
  /* dvh (with the vh fallback for older engines) so the rail matches the
     VISIBLE viewport on mobile — with 100vh the profile trigger sits under
     the browser's collapsing URL bar and can't be reached. */
  height: 100vh; height: 100dvh;
  /* Above the standard right-side drawer (z-index 51) and below modal
     dialogs (z-index 100+). Defensive: keeps the sidebar dependable
     as the topmost piece of page chrome. */
  z-index: 60;
}
.brand {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px 18px; border-bottom: 1px solid var(--line-2); margin-bottom: 14px;
  flex: 0 0 auto;
}

/* Nav rail — the sidebar's ONLY scrollable region (§ 8.4.2). Every
   nav-section / nav-item lives in here.

   `min-height: 0` is load-bearing, not tidying: a flex item's default
   `min-height: auto` refuses to shrink below its content, so a long
   role-gated nav (FS System Admin on a short viewport) grew past the
   sidebar's 100dvh box. Overflow stayed VISIBLE, which still extends the
   document's scrollable area — and because the sticky sidebar's containing
   block is exactly one viewport tall, its stuck offset clamps to 0, so the
   whole shell scrolled away and left a dead zone below the page.

   The scroll region deliberately stops short of .sidebar-foot: the profile
   popover is absolutely positioned out of the foot (upward when expanded,
   sideways when collapsed) and an ancestor scroll container would clip it. */
.sidebar-nav {
  display: flex; flex-direction: column; gap: 4px;
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin;
  /* Bleed the track into the sidebar's own padding so the nav pills keep
     their full width and the scrollbar hugs the right divider. */
  margin-right: -6px; padding-right: 6px;
}
.brand-mark {
  width: 28px; height: 28px; border-radius: var(--r-4);
  background: var(--primary); color: #fff;
  display: grid; place-items: center;
  flex: 0 0 auto;
  overflow: hidden;
}
.brand-mark svg { width: 16px; height: 16px; }
.brand-mark-img {
  width: 22px; height: 22px;
  object-fit: contain;
  display: block;
}
/* Text column next to the logo. flex: 1 + min-width: 0 lets long company
   names ellipsis without pushing the layout wide. */
.brand-text { flex: 1; min-width: 0; }
.brand-name { font-weight: 700; color: var(--ink); letter-spacing: -0.01em; font-size: var(--fs-15); }
.brand-tag {
  font-size: var(--fs-11); color: var(--soft); letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; margin-top: 1px;
}

.nav-section {
  font-size: var(--fs-11); text-transform: uppercase; letter-spacing: .1em;
  color: var(--soft); padding: 12px 10px 6px;
}
.nav-item {
  display: flex; align-items: center; gap: var(--sp-5);
  padding: var(--sp-4) var(--sp-5); border-radius: var(--r-3);
  color: var(--ink-2); cursor: pointer;
  font-size: var(--fs-14); font-weight: 500;
  text-decoration: none; user-select: none;
  transition: background var(--dur-1), color var(--dur-1);
  /* button reset — so .nav-item works on both <a> and <button> */
  background: transparent; border: 0; width: 100%;
  text-align: left; font-family: inherit;
}
.nav-item i        { font-size: 16px; color: var(--muted); width: 16px; }
.nav-item:hover    { background: var(--bg); }
.nav-item.is-active   { background: var(--primary-50); color: var(--primary); }
.nav-item.is-active i { color: var(--primary); }
.nav-item.is-disabled { color: var(--soft); cursor: default; }
.nav-item.is-disabled:hover { background: transparent; }
.nav-item.is-disabled i { color: var(--soft); }

.nav-item .count {
  margin-left: auto; font-size: var(--fs-12); color: var(--muted);
  background: var(--bg); padding: 1px 7px; border-radius: 8px; font-weight: 600;
  font-feature-settings: "tnum";
}
.nav-item.is-active .count { background: #fff; color: var(--primary); }

.sidebar-foot {
  margin-top: auto; padding-top: 14px; border-top: 1px solid var(--line-2);
  position: relative;
  /* Never compress or scroll: the profile trigger stays reachable at every
     viewport height; .sidebar-nav absorbs the leftover space instead. */
  flex: 0 0 auto;
}

/* -----------------------------------------------------------
   Sidebar — collapsed (icons-only) variant.
   Driven by a single class on <html> so a tiny inline script
   in App.razor can apply it from localStorage BEFORE Blazor
   mounts (see DESIGN.md § 8.4). The class is also toggled by
   MainLayout's collapse button via the tkSidebar JS helper.
   The single var(--layout-sidebar) override flows through the
   .app grid AND every consumer (drawer left:, content offsets,
   etc.) without any other selectors needing to know.
   ----------------------------------------------------------- */
html.tk-sidebar-collapsed .app { --layout-sidebar: var(--layout-sidebar-collapsed); }

html.tk-sidebar-collapsed .sidebar { padding: 18px 6px; }

/* The expanded rail bleeds its scroll track into a 14 px side padding; the
   collapsed rail only has 6 px, so drop the bleed rather than let the track
   sit on top of the right divider. The scrollbar stays VISIBLE (an icons-only
   rail that silently hides overflowing items is the bug this fixes) — it just
   nudges the icons a few px left while the rail is actually scrollable. */
html.tk-sidebar-collapsed .sidebar-nav { margin-right: 0; padding-right: 0; }

/* Brand row collapses to just the mark, centered. */
html.tk-sidebar-collapsed .brand {
  justify-content: center;
  padding: 6px 0 18px;
}
html.tk-sidebar-collapsed .brand-text { display: none; }

/* Nav-section eyebrows hide entirely in icons-only mode. Keeping the
   text via `height: 0; overflow: hidden` proved unreliable across
   browsers (the padding still rendered and clipped text bled through
   in some box-sizing combinations). The icon stack reads fine without
   group headers; if visual grouping is needed later, replace this
   with a 1px divider (`background: var(--line-2); height: 1px;`). */
html.tk-sidebar-collapsed .nav-section { display: none; }

/* Nav items: icon-only, centered. */
html.tk-sidebar-collapsed .nav-item {
  justify-content: center;
  padding: var(--sp-4) 0;
  gap: 0;
}
html.tk-sidebar-collapsed .nav-item i {
  width: auto;
  font-size: 19px;
}
html.tk-sidebar-collapsed .nav-label,
html.tk-sidebar-collapsed .nav-item .count { display: none; }

/* Profile trigger: just the avatar, centered. */
html.tk-sidebar-collapsed .profile-trigger {
  justify-content: center;
  padding: 6px 4px;
}
html.tk-sidebar-collapsed .profile-trigger .avatar-meta,
html.tk-sidebar-collapsed .profile-trigger .chev { display: none; }

/* Profile popover anchors to the right of the avatar in collapsed
   mode (instead of spanning the sidebar width, which would now be
   only 64 px wide). */
html.tk-sidebar-collapsed .profile-pop {
  left: calc(100% + 8px);
  right: auto;
  width: 240px;
  bottom: 0;
}

/* -----------------------------------------------------------
   Profile trigger + popover (§ 8.5)
   ----------------------------------------------------------- */
.profile-trigger {
  width: 100%;
  background: transparent; border: 0; cursor: pointer; font-family: inherit;
  display: flex; align-items: center; gap: 10px; padding: 6px; margin: 0;
  border-radius: var(--r-5); color: inherit; text-align: left;
  transition: background var(--dur-1);
}
.profile-trigger:hover { background: var(--bg); }
.profile-trigger .chev {
  margin-left: auto; color: var(--soft); font-size: 13px;
  transition: transform var(--dur-2);
}
.profile-trigger[aria-expanded="true"] .chev { transform: rotate(180deg); color: var(--ink-2); }

.profile-pop {
  position: absolute;
  bottom: calc(100% + 6px); left: 0; right: 0;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-6);
  box-shadow: var(--shadow-3);
  padding: 6px;
  opacity: 0; transform: translateY(4px) scale(.98);
  transform-origin: bottom center;
  pointer-events: none;
  transition: opacity var(--dur-3) ease, transform var(--dur-3) ease;
  z-index: 30;
}
.profile-pop.is-open { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.profile-pop-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 10px 12px; border-bottom: 1px solid var(--line-2); margin-bottom: 6px;
}
/* Text container next to the avatar — must allow shrinking so .truncate ellipsis kicks in. */
.profile-pop-head-meta { flex: 1; min-width: 0; }
.profile-pop-head .name  { font-weight: 600; color: var(--ink); font-size: var(--fs-14); line-height: var(--lh-tight); }
.profile-pop-head .email { font-size: var(--fs-125); color: var(--muted); margin-top: 1px; line-height: var(--lh-tight); }

.profile-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px; border-radius: var(--r-3);
  color: var(--ink-2); font-size: var(--fs-14); font-weight: 500;
  text-decoration: none; cursor: pointer; user-select: none;
  background: transparent; border: 0; width: 100%; text-align: left; font-family: inherit;
}
.profile-item i { font-size: 16px; color: var(--muted); width: 16px; }
.profile-item:hover    { background: var(--bg); }
.profile-item:hover i  { color: var(--ink-2); }
.profile-item.is-danger        { color: var(--error); }
.profile-item.is-danger i      { color: var(--error); }
.profile-item.is-danger:hover  { background: rgba(239,68,68,.06); }
.profile-pop-sep { height: 1px; background: var(--line-2); margin: 6px 0; }

/* -----------------------------------------------------------
   Avatar (§ 9.8)
   ----------------------------------------------------------- */
.avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto;
  background: linear-gradient(135deg, #011E5C, #2f4b91);
  color: #fff; display: grid; place-items: center;
  font-weight: 600; font-size: var(--fs-12);
}
.avatar--sm { width: 24px; height: 24px; font-size: 10px; }
.avatar--lg { width: 34px; height: 34px; font-size: var(--fs-13); }
.avatar--xl { width: 56px; height: 56px; font-size: 19px; }
/* Photo variant — rendered by Components/Shared/UserAvatar.razor when the user has a
   profile picture. Same disc geometry; the image replaces the gradient. */
.avatar--img { object-fit: cover; background: var(--card); }
/* Text column next to an avatar in flex rows. min-width: 0 lets .truncate
   ellipsis work even when the text is longer than the available space. */
.avatar-meta { line-height: var(--lh-tight); flex: 1; min-width: 0; }
.avatar-name { font-weight: 600; color: var(--ink); font-size: var(--fs-135); }
.avatar-role { font-size: var(--fs-12); color: var(--soft); }

/* -----------------------------------------------------------
   Topbar (§ 8.7)
   ----------------------------------------------------------- */
.topbar {
  height: var(--layout-topbar); padding: 0 28px;
  border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,.85); backdrop-filter: blur(8px);
  display: flex; align-items: center; gap: 16px;
  position: sticky; top: 0; z-index: 10;
}
.crumbs { font-size: var(--fs-135); color: var(--muted); display: flex; align-items: center; gap: 6px; }
.crumbs strong { color: var(--ink); font-weight: 600; }
.crumbs i      { font-size: 12px; color: var(--soft); }
.crumbs a      { color: inherit; text-decoration: none; }
.crumbs a:hover { color: var(--ink); }

.search {
  margin-left: 8px; flex: 1; max-width: 420px;
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px; border: 1px solid var(--line);
  border-radius: var(--r-5); background: var(--bg);
  color: var(--muted); font-size: var(--fs-135);
}
.search input { border: 0; background: transparent; outline: none; flex: 1;
                font-size: var(--fs-135); color: var(--ink-2); font-family: inherit; }
.search kbd   { font-family: var(--font-mono); font-size: 11px; padding: 2px 6px;
                border-radius: var(--r-2); background: #fff; border: 1px solid var(--line);
                color: var(--muted); }

.top-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

@media (max-width: 1100px) {
  .top-actions .btn-ghost .label-export { display: none; }
  .top-actions .btn-ghost { padding: 7px 9px; }
  .search { max-width: 240px; }
}
@media (max-width: 920px) {
  .crumbs { display: none; }
  .search { max-width: 200px; }
}

/* -----------------------------------------------------------
   Buttons (§ 9.1)
   ----------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: var(--r-5);
  font-size: var(--fs-135); font-weight: 600;
  cursor: pointer; border: 1px solid transparent; font-family: inherit;
  transition: background var(--dur-1), border-color var(--dur-1), color var(--dur-1);
  text-decoration: none;
}
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-primary  { background: var(--primary); color: #fff; }
.btn-primary:hover  { background: var(--primary-700); }
.btn-ghost    { background: #fff; color: var(--ink-2); border-color: var(--line); }
.btn-ghost:hover    { background: var(--bg); }
.btn-danger   { background: #fff; color: var(--error); border-color: rgba(239,68,68,.25); }
.btn-danger:hover   { background: var(--error-soft); }

.btn--sm  { padding: 5px 10px; font-size: 13px; }
.btn--lg  { padding: 9px 16px; font-size: 14px; }

/* -----------------------------------------------------------
   Icon button (§ 9.2)
   ----------------------------------------------------------- */
.icon-btn {
  width: 34px; height: 34px; border-radius: var(--r-5);
  border: 1px solid var(--line); background: #fff;
  display: grid; place-items: center; cursor: pointer; color: var(--ink-2);
  position: relative; transition: background var(--dur-1);
  font-family: inherit;
}
.icon-btn:hover { background: var(--bg); }
.icon-btn .dot {
  position: absolute; top: 7px; right: 8px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--error); border: 2px solid #fff;
}
.icon-btn--sm { width: 30px; height: 30px; border-radius: var(--r-4); }

/* -----------------------------------------------------------
   Inputs / selects / textareas (§ 9.3)
   ----------------------------------------------------------- */
.input, .select, textarea.input {
  width: 100%; padding: 9px 11px;
  border: 1px solid var(--line); border-radius: var(--r-4);
  font-family: inherit; font-size: var(--fs-14); color: var(--ink-2);
  background: #fff; outline: none;
  transition: border-color var(--dur-1), box-shadow var(--dur-1);
}
.input:hover, .select:hover { border-color: #d8dde7; }
.input:focus, .select:focus, textarea.input:focus {
  border-color: var(--primary);
  box-shadow: var(--ring-primary);
}
.input::placeholder { color: var(--soft); }
textarea.input { resize: vertical; min-height: 80px; }

.input--error, .select--error {
  border-color: var(--error);
  box-shadow: var(--ring-error);
}
.input--num { font-feature-settings: "tnum"; }

.select {
  appearance: none; -webkit-appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238898aa' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center;
}

.input-prefix { position: relative; }
.input-prefix .input { padding-left: 28px; }
.input-prefix .pfx   { position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
                       color: var(--soft); font-size: 13px; pointer-events: none; }

/* Read-only field display (§ 9.3 addition for ViewClientOrderStatus) */
.readonly-value {
  width: 100%; padding: 9px 11px; min-height: 36px;
  border: 1px solid var(--line-2); border-radius: var(--r-4);
  background: var(--bg); color: var(--ink); font-size: var(--fs-14);
  font-family: inherit; font-feature-settings: "tnum";
  white-space: pre-wrap; word-break: break-word;
}
.readonly-value.is-empty { color: var(--soft); font-style: italic; }
.readonly-value--mono { font-family: var(--font-mono); }

/* -----------------------------------------------------------
   Field & label (§ 9.4)
   ----------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.field.col-span-2 { grid-column: span 2; }
.label {
  font-size: var(--fs-125); font-weight: 600; color: var(--ink-2);
  display: flex; align-items: center; gap: 6px;
}
.label .req { color: var(--error); font-weight: 700; }
.label .opt {
  color: var(--soft); font-weight: 500; font-size: 11.5px;
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
}
.help        { font-size: 12px; color: var(--soft); }
.field-error { font-size: 12px; color: var(--error); display: flex; align-items: center; gap: 4px; }
.field-error i { font-size: 12px; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 16px; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px 16px; }
.grid-4 { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 14px 16px; }
@media (max-width: 720px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}

/* -----------------------------------------------------------
   Card (§ 9.5)
   ----------------------------------------------------------- */
.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-6); overflow: hidden;
}
.card-head {
  padding: 14px 18px; border-bottom: 1px solid var(--line-2);
  display: flex; align-items: center; gap: 10px;
}
.card-title  { font-size: var(--fs-145); font-weight: 700; color: var(--ink);
               margin: 0; letter-spacing: -0.005em; }
.card-sub    { font-size: 13px; color: var(--muted); margin-left: 8px; }
.card-actions{ margin-left: auto; display: flex; gap: 6px; align-items: center; }
.card-body   { padding: 14px 18px; }
.card-foot   { padding: 12px 18px; border-top: 1px solid var(--line-2);
               display: flex; align-items: center; gap: 8px; }
.card-body--flush { padding: 0; }

/* -----------------------------------------------------------
   Badge / pill (§ 9.6)
   ----------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-pill);
  font-size: var(--fs-12); font-weight: 600; white-space: nowrap;
}
.badge i { font-size: 11px; }

.b-passed   { background: var(--success-soft);  color: #0a9558; }
.b-waived   { background: var(--warning-soft);  color: var(--warning-dark); }
.b-failed   { background: var(--error-soft);    color: var(--error); }
.b-progress { background: var(--primary-100);   color: var(--primary); }
.b-review   { background: var(--gray-soft);     color: #4b5563; }

/* Retired marker (§ 9.6a). Shared muted pill composed onto `.badge b-review`, used wherever
   something the product no longer offers is still displayed for historical context. Two distinct
   predicates carry this same badge — see DESIGN.md § 9.6a before adding a third. The generated
   diligence-report PDF defines its OWN copy of this rule locally: that document does not load the
   design system, so this file never reaches it. */
.retired-badge { margin-left: 6px; }

/* -----------------------------------------------------------
   Progress bar (§ 9.7)
   ----------------------------------------------------------- */
.progress {
  width: 110px; height: 5px; background: var(--line);
  border-radius: var(--r-pill); overflow: hidden;
}
.progress > span { display: block; height: 100%; transition: width var(--dur-5) var(--ease); }
.progress--thin { height: 4px; }
.progress--block { width: 100%; }

/* -----------------------------------------------------------
   Filter chip (§ 9.9)
   ----------------------------------------------------------- */
.filters {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 18px; border-bottom: 1px solid var(--line-2); flex-wrap: wrap;
}
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: var(--r-pill); border: 1px solid var(--line);
  font-size: 12.5px; font-weight: 500; color: var(--ink-2);
  background: #fff; cursor: pointer; font-family: inherit;
  transition: background var(--dur-1);
}
.chip i      { font-size: 12px; color: var(--soft); }
.chip:hover  { background: var(--bg); }
.chip.is-on  { background: var(--ink); color: #fff; border-color: var(--ink); }
.chip.is-on i { color: rgba(255,255,255,.7); }
.chip-num    { opacity: .6; margin-left: 2px; font-weight: 500; font-feature-settings: "tnum"; }
.chip.is-on .chip-num { opacity: .7; }

/* -----------------------------------------------------------
   KPI tile (§ 9.10)
   ----------------------------------------------------------- */
.kpis {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px; margin-bottom: 22px;
}
@media (max-width: 1080px) { .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.kpi {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-6); padding: 16px 18px;
  position: relative; overflow: hidden;
}
.kpi-label {
  font-size: var(--fs-12); font-weight: 600; color: var(--soft);
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
}
.kpi-value {
  font-size: var(--fs-30); font-weight: 700; color: var(--ink);
  letter-spacing: var(--tracking-tight); margin-top: 8px;
  line-height: 1; font-feature-settings: "tnum";
}
.kpi-value .unit { font-size: 15px; color: var(--muted); font-weight: 600; margin-left: 3px; }
.kpi-trend {
  font-size: 12.5px; margin-top: 10px;
  display: inline-flex; align-items: center; gap: 4px; font-weight: 600;
}
.kpi-trend.up   { color: var(--success); }
.kpi-trend.down { color: var(--error); }
.kpi-trend.flat { color: var(--muted); }
.kpi-trend span { color: var(--muted); font-weight: 500; }

/* KPI as a fact (smaller value, e.g. order header chips) */
.kpi--fact .kpi-value { font-size: var(--fs-15); margin-top: 6px; line-height: var(--lh-tight); }
.kpi--fact .kpi-value.is-mono { font-family: var(--font-mono); }
.kpi--fact { padding: 12px 14px; }

/* -----------------------------------------------------------
   Pipeline stage strip (§ 9.11)
   ----------------------------------------------------------- */
.pipeline {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 1px;
  background: var(--line-2);
}
.stage {
  background: #fff; padding: 14px 16px;
  cursor: pointer; transition: background var(--dur-2);
}
.stage:hover { background: var(--bg); }
.stage-name {
  font-size: var(--fs-12); font-weight: 600; color: var(--soft);
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
}
.stage-count {
  font-size: 24px; font-weight: 700; color: var(--ink);
  margin-top: 6px; line-height: 1; font-feature-settings: "tnum";
}
.stage-bar  { height: 3px; border-radius: 2px; background: var(--line);
              margin-top: 12px; overflow: hidden; }
.stage-bar > span { display: block; height: 100%; }
.stage-meta {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 8px; font-size: 12px; color: var(--muted);
}

/* -----------------------------------------------------------
   Activity item (§ 9.12)
   ----------------------------------------------------------- */
.activity-list { padding: 4px 0; }
.activity {
  display: grid; grid-template-columns: 28px 1fr;
  gap: 12px; padding: 12px 18px;
  border-bottom: 1px solid var(--line-2);
}
.activity:last-child { border-bottom: 0; }
.activity-mark {
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center; flex: 0 0 auto;
  background: var(--primary-100); color: var(--primary);
}
.activity-mark.success { background: var(--success-soft); color: #0a9558; }
.activity-mark.warning { background: var(--warning-soft); color: var(--warning-dark); }
.activity-mark.error   { background: var(--error-soft);   color: var(--error); }
.activity-mark i       { font-size: 14px; }
.activity-text  { font-size: var(--fs-135); color: var(--ink-2); }
.activity-text strong { font-weight: 600; color: var(--ink); }
.activity-time  {
  font-size: 12px; color: var(--soft); margin-top: 2px;
  font-feature-settings: "tnum";
}

/* -----------------------------------------------------------
   SLA bar (§ 9.13)
   ----------------------------------------------------------- */
.sla-row { }
.sla-label-line { display: flex; justify-content: space-between; font-size: 13px; }
.sla-label-line .label { color: var(--ink-2); font-weight: 600; }
.sla-label-line .val   { color: var(--muted); font-feature-settings: "tnum"; }
.sla-bar {
  height: 5px; background: var(--line); border-radius: 3px;
  margin-top: 8px; overflow: hidden;
}
.sla-bar > span {
  display: block; height: 100%; border-radius: 3px;
  transition: width var(--dur-5) var(--ease);
}

/* SLA-warning text (replaces legacy .sla-warning + smoothFlash) */
.sla-warn { color: var(--error); font-weight: 600; }
.sla-ok   { color: var(--success); }

.sla-breached-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-pill);
  font-size: var(--fs-12); font-weight: 700;
  background: var(--error); color: #fff;
}

/* -----------------------------------------------------------
   Stepper (§ 9.14)
   ----------------------------------------------------------- */
.stepper {
  display: flex; align-items: center; width: 100%; gap: 8px; padding: 12px 0;
  list-style: none; margin: 0;
}
.step {
  position: relative; min-width: 120px; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.step-circle {
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--line); color: var(--muted);
  display: grid; place-items: center;
  font-weight: 600; font-feature-settings: "tnum";
}
.step-label {
  font-size: var(--fs-14); font-weight: 500; color: var(--muted);
  letter-spacing: 0.2px;
}
.step-line { flex: 1; height: 1px; background: var(--line); }

.step.is-active .step-circle    { background: var(--primary);  color: #fff; }
.step.is-active .step-label     { color: var(--primary); }
.step.is-complete .step-circle  { background: var(--success);  color: #fff; }
.step.is-complete .step-label   { color: var(--success); }
.step-line.is-complete          { background: var(--success); }
.step-line.is-active            { background: var(--primary); }

/* Vertical stepper variant (used by ApiDocumentation Quick Start) */
.stepper--vertical {
  flex-direction: column; align-items: flex-start; gap: 14px; padding: 8px 0;
}
.stepper--vertical .step {
  flex-direction: row; align-items: flex-start; min-width: 0; width: 100%;
  text-align: left; gap: 12px;
}
.stepper--vertical .step-circle { width: 28px; height: 28px; font-size: 14px; flex: 0 0 auto; }
.stepper--vertical .step-content { flex: 1; min-width: 0; padding-top: 3px; }

/* -----------------------------------------------------------
   Tabs (§ 9.15) — used by ApiDocumentation + ViewClientOrderStatus
   ----------------------------------------------------------- */
.tabs {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px; background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--r-5);
}
.tabs--block { display: flex; width: 100%; }
.tab {
  padding: 6px 12px; font-size: var(--fs-135); font-weight: 600;
  color: var(--muted); border-radius: var(--r-3); cursor: pointer;
  background: transparent; border: 0; font-family: inherit;
  transition: all var(--dur-1);
}
.tabs--block .tab { flex: 1; text-align: center; }
.tab:hover { color: var(--ink); }
.tab.is-active {
  background: #fff; color: var(--ink); box-shadow: var(--shadow-1);
}

.tab-panels { margin-top: 16px; }
.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

/* -----------------------------------------------------------
   Table (§ 10.1)
   ----------------------------------------------------------- */
.tbl { width: 100%; border-collapse: collapse; font-size: var(--fs-135); }

.tbl thead th {
  text-align: left; font-weight: 600; font-size: 11.5px;
  color: var(--soft); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
  padding: 10px 18px; background: var(--card);
  border-bottom: 1px solid var(--line-2);
  white-space: nowrap; user-select: none;
}
.tbl thead th.is-sortable        { cursor: pointer; }
.tbl thead th.is-sortable:hover  { color: var(--ink-2); }
.tbl thead th.is-sorted          { color: var(--ink); }
.tbl thead th .sort-ic           { margin-left: 4px; opacity: .55; font-size: 11px; vertical-align: middle; }
.tbl thead th.is-sorted .sort-ic { opacity: 1; color: var(--primary); }

.tbl tbody td        { padding: 12px 18px; border-bottom: 1px solid var(--line-2); vertical-align: middle; }
.tbl tbody tr        { transition: background var(--dur-1); }
.tbl tbody tr.is-clickable { cursor: pointer; }
.tbl tbody tr.is-clickable:hover { background: var(--bg); }
.tbl tbody tr.is-selected { background: var(--primary-50); }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl tbody tr.row-aging-critical    td       { background: rgba(239,68,68,.04); }
.tbl tbody tr.row-aging-critical:hover td    { background: rgba(239,68,68,.08); }

.order-id    { font-family: var(--font-mono); font-size: 13px; color: var(--ink); font-weight: 500;
               font-feature-settings: "tnum"; }
.prop-line   { color: var(--ink); font-weight: 600; }
.prop-sub    { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

.client      { display: flex; align-items: center; gap: 8px; }
.client-mark { width: 24px; height: 24px; border-radius: 6px;
               background: var(--primary-100); color: var(--primary);
               display: grid; place-items: center; font-weight: 700; font-size: 11.5px; }

.age         { display: inline-flex; flex-direction: column; line-height: 1.15; }
.age .big    { font-size: 14.5px; font-weight: 700; color: var(--ink); font-feature-settings: "tnum"; }
.age .sub    { font-size: 12px; color: var(--muted); margin-top: 1px; }
.age.is-aging .big    { color: var(--warning-dark); }
.age.is-critical .big { color: var(--error); }

.row-icon-btn {
  background: transparent; border: 1px solid transparent;
  width: 26px; height: 26px; border-radius: 6px;
  display: grid; place-items: center; cursor: pointer; color: var(--soft);
  font-family: inherit;
}
.row-icon-btn:hover:not(:disabled)         { background: #fff; color: var(--ink); border-color: var(--line); }
.row-icon-btn.is-danger:hover:not(:disabled) { color: var(--error); border-color: rgba(239,68,68,.2); background: var(--error-soft); }
.row-icon-btn:disabled      { opacity: .5; cursor: not-allowed; }

.table-foot {
  padding: 10px 18px; border-top: 1px solid var(--line-2);
  display: flex; align-items: center; gap: 12px;
  font-size: 13px; color: var(--muted);
}
.pager      { margin-left: auto; display: flex; gap: 4px; align-items: center; }
.page-btn   {
  height: 28px; min-width: 28px; padding: 0 8px;
  border: 1px solid var(--line); background: #fff; border-radius: 6px;
  font-size: 13px; color: var(--ink-2); cursor: pointer; font-family: inherit;
}
.page-btn:hover     { background: var(--bg); }
.page-btn.is-active { background: var(--primary); color: #fff; border-color: var(--primary); }
.page-btn:disabled  { opacity: .4; cursor: not-allowed; }

/* -----------------------------------------------------------
   Drawer (§ 10.2)
   ----------------------------------------------------------- */
.drawer-backdrop {
  position: fixed; inset: 0; background: rgba(10,37,64,.32); z-index: 50;
  opacity: 0; pointer-events: none; transition: opacity var(--dur-3);
}
.drawer-backdrop.is-open { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: 480px; max-width: 92vw;
  background: #fff; border-left: 1px solid var(--line); z-index: 51;
  transform: translateX(100%); transition: transform var(--dur-4) var(--ease);
  display: flex; flex-direction: column;
  box-shadow: var(--shadow-4);
}
.drawer.is-open       { transform: translateX(0); }
.drawer-head          {
  padding: 18px 22px; border-bottom: 1px solid var(--line-2);
  display: flex; align-items: flex-start; gap: 12px;
}
.drawer-head .icon-btn { margin-left: auto; }
.drawer-body          { padding: 18px 22px; overflow-y: auto; flex: 1; }
.drawer-foot          {
  padding: 14px 22px; border-top: 1px solid var(--line-2);
  display: flex; gap: 8px; justify-content: flex-end;
}

/* Wide variant for document viewers (§ 10.2 addendum) */
.drawer--wide { width: 70vw; max-width: 1100px; }
.drawer--wide .drawer-body { padding: 0; }

/* Inline reference panes — for non-modal side rails that share the
   page's flow rather than overlaying it — are page-local patterns
   (see DESIGN.md § 10.2.2 for the EditClientOrder Documents pane).
   They reuse .drawer-head / .drawer-body for visual consistency but
   are not a .drawer variant. */

/* -----------------------------------------------------------
   Dialog (§ 10.3)
   ----------------------------------------------------------- */
.dlg-backdrop {
  position: fixed; inset: 0; background: rgba(10,37,64,.4);
  z-index: 100; opacity: 0; pointer-events: none;
  transition: opacity var(--dur-3);
}
.dlg-backdrop.is-open { opacity: 1; pointer-events: auto; }

.dlg {
  position: fixed; top: 50%; left: 50%;
  transform: translate(-50%, -48%) scale(.98);
  width: 640px; max-width: 92vw; max-height: 88vh;
  background: #fff; border-radius: var(--r-7);
  box-shadow: var(--shadow-5); z-index: 101;
  display: flex; flex-direction: column;
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-3), transform var(--dur-4) var(--ease);
}
.dlg.is-open  {
  opacity: 1; pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}

.dlg-head     {
  padding: 18px 22px 14px; border-bottom: 1px solid var(--line-2);
  display: flex; align-items: flex-start; gap: 10px;
}
.dlg-title    { font-size: 16px; font-weight: 700; color: var(--ink); margin: 0; }
.dlg-sub      { font-size: 13px; color: var(--muted); margin-top: 2px; }
.dlg-head .icon-btn { margin-left: auto; }
.dlg-body     { padding: 18px 22px; overflow-y: auto; flex: 1; }
.dlg-foot     {
  padding: 12px 22px; border-top: 1px solid var(--line-2);
  display: flex; gap: 8px; justify-content: flex-end; align-items: center;
}
.dlg-foot-left{ margin-right: auto; font-size: 13px; color: var(--muted); }
.dlg-error    { color: var(--error); font-weight: 600; font-size: 13px; }
/* Footer inside a HOSTED dialog body (the IAppDialog / Radzen shell already pads
   .rz-dialog-content 18px 22px), where .dlg-foot's own 22px inset would double up
   and push the buttons off the content's left edge. Keeps the rule (border-top +
   right-aligned button row), drops the horizontal padding. */
.dlg-foot--flush { padding: 14px 0 0; }

.dlg--sm { width: 480px; }
.dlg--lg { width: 800px; }

/* -----------------------------------------------------------
   Sticky checklist (§ 10.4)
   ----------------------------------------------------------- */
/* The new-order form caps narrower (1280) than the global .content default (1480) so the
   form + sticky checklist read comfortably. The width is SHARED with .content--narrow so the
   page's non-grid states (loading / empty) cap at the SAME width — otherwise the centred
   container, and the "New order" title with it, shifts ~100px horizontally when the page
   transitions between its loading and loaded states. Keep both selectors on one rule. */
.content--with-checklist,
.content--narrow { max-width: 1280px; }

.content--with-checklist {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 28px;
  align-items: start;
  padding-bottom: 80px;
}
@media (max-width: 980px) {
  .content--with-checklist { grid-template-columns: 1fr; }
  .content--with-checklist .checklist { position: static !important; }
}

.content--with-checklist .page-head { grid-column: 1 / -1; }

.checklist {
  position: sticky; top: 80px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-6); padding: 8px; align-self: start;
}
.cl-head            {
  padding: 10px 12px 12px; border-bottom: 1px solid var(--line-2); margin-bottom: 6px;
}
.cl-title           {
  font-size: var(--fs-12); font-weight: 700; color: var(--soft);
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow); margin: 0 0 8px;
}
.cl-progress-bar    { height: 4px; background: var(--line); border-radius: var(--r-pill); overflow: hidden; }
.cl-progress-bar > span {
  display: block; height: 100%; background: var(--primary);
  transition: width var(--dur-5) var(--ease);
}
.cl-progress-text   {
  font-size: 12.5px; color: var(--muted); margin-top: 6px;
  font-feature-settings: "tnum";
}
.cl-progress-text strong { color: var(--ink); font-weight: 600; }

.cl-item            {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: var(--r-3);
  cursor: pointer; color: var(--ink-2);
  font-size: var(--fs-135); font-weight: 500;
  text-decoration: none; transition: background var(--dur-1);
  /* Reset button-element defaults so a <button class="cl-item"> looks
     identical to the <a class="cl-item"> variant. */
  background: transparent; border: 0; width: 100%;
  text-align: left; font-family: inherit;
}
.cl-item:hover      { background: var(--bg); }
.cl-item.is-active  { background: var(--primary-50); color: var(--primary); font-weight: 600; }
.cl-item.is-complete { color: var(--ink); }
.cl-mark            {
  width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--line); background: #fff;
  display: grid; place-items: center; flex: 0 0 auto;
  font-size: 11px; color: var(--soft);
  transition: all .25s ease;
}
.cl-item.is-active .cl-mark   { border-color: var(--primary); color: var(--primary); }
.cl-item.is-complete .cl-mark { background: var(--success); border-color: var(--success); color: #fff; }
.cl-item.is-complete .cl-mark i { font-size: 12px; }
.cl-name            {
  flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.cl-meta            { font-size: 11.5px; color: var(--soft); font-feature-settings: "tnum"; }
.cl-item.is-complete .cl-meta { color: var(--success); }
.cl-item.is-active .cl-meta   { color: var(--primary); }

/* Form sections (§ 10.4) */
.form-col           { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.section            {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-6); overflow: hidden; scroll-margin-top: 80px;
}
.section-head       {
  padding: 14px 20px; border-bottom: 1px solid var(--line-2);
  display: flex; align-items: center; gap: 12px;
}
.section-icon       {
  width: 28px; height: 28px; border-radius: var(--r-4);
  background: var(--primary-50); color: var(--primary);
  display: grid; place-items: center; flex: 0 0 auto;
  transition: background .25s, color .25s;
}
.section.is-complete .section-icon { background: var(--success-soft); color: var(--success); }
.section-icon i     { font-size: 15px; }
.section-title      {
  font-size: var(--fs-15); font-weight: 700; color: var(--ink); margin: 0;
  letter-spacing: -0.005em;
}
.section-sub        { font-size: 12.5px; color: var(--muted); margin-top: 1px; }
.section-status     {
  margin-left: auto; font-size: 12.5px; color: var(--muted);
  display: flex; align-items: center; gap: 6px;
}
.section.is-complete .section-status { color: var(--success); font-weight: 600; }
.section-body       { padding: 18px 20px 20px; }
.section-body--flush { padding: 0; }

/* Sticky submit bar (§ 10.4) */
.submit-bar         {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px; background: #fff;
  border: 1px solid var(--line); border-radius: var(--r-6);
  position: sticky; bottom: 16px;
  box-shadow: var(--shadow-2);
}
.submit-bar .summary { font-size: var(--fs-135); color: var(--muted); }
.submit-bar .summary strong { color: var(--ink); font-weight: 600; }
.submit-bar .actions { margin-left: auto; display: flex; gap: 8px; }

/* -----------------------------------------------------------
   File uploader (§ 10.5)
   ----------------------------------------------------------- */
.uploader      {
  border: 1.5px dashed var(--line); border-radius: var(--r-6);
  padding: 28px 20px; background: var(--bg); text-align: center;
  transition: all var(--dur-2); cursor: pointer;
}
.uploader:hover, .uploader.is-drag { border-color: var(--primary); background: var(--primary-50); }
.uploader-ic   {
  width: 40px; height: 40px; border-radius: var(--r-6);
  background: #fff; border: 1px solid var(--line);
  display: grid; place-items: center; margin: 0 auto 10px;
  color: var(--primary);
}
.uploader-ic i { font-size: 19px; }
.uploader-title { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.uploader-sub  { font-size: 13px; color: var(--muted); margin-top: 4px; }
.uploader-pick { color: var(--primary); font-weight: 600; }

.file-list { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; }
.file-row      {
  display: grid;
  grid-template-columns: 36px 1fr 220px 28px;
  gap: 12px; align-items: center;
  padding: 10px 12px;
  border: 1px solid var(--line-2); border-radius: var(--r-5);
  background: #fff;
}
.file-row.is-clickable { cursor: pointer; transition: background var(--dur-1); }
.file-row.is-clickable:hover { background: var(--bg); }
.file-ic       {
  width: 36px; height: 36px; border-radius: var(--r-4);
  background: var(--primary-50); color: var(--primary);
  display: grid; place-items: center; flex: 0 0 auto;
}
.file-ic i     { font-size: 17px; }
.file-meta     { min-width: 0; }
.file-name     {
  font-size: var(--fs-135); font-weight: 600; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.file-size     {
  font-size: 12px; color: var(--soft); margin-top: 1px;
  font-feature-settings: "tnum";
}
.file-progress {
  height: 3px; background: var(--line); border-radius: var(--r-pill);
  margin-top: 6px; overflow: hidden;
}
.file-progress > span { display: block; height: 100%; background: var(--success);
                        transition: width var(--dur-5) var(--ease); }
.file-x        {
  background: transparent; border: 0; color: var(--soft); cursor: pointer;
  width: 28px; height: 28px; border-radius: var(--r-3);
  font-family: inherit;
}
.file-x:hover  { background: var(--bg); color: var(--error); }

/* file-row variant with extra "uploaded by" column for ViewClientOrderStatus */
.file-row--detail {
  grid-template-columns: 36px 1fr 220px 200px 28px;
}

/* Inert row — present for context but not actionable (e.g. the (tenant, product) already
   open in the editor inside the Copy-form picker). Dims the whole row so it reads disabled
   at a glance rather than only via its badge. Never combine with .is-clickable. */
.file-row--disabled {
  opacity: .55;
  cursor: default;
}

/* -----------------------------------------------------------
   Document group accordion (§ 10.8) — used by ViewClientOrderStatus
   ----------------------------------------------------------- */
.doc-group { border: 1px solid var(--line-2); border-radius: var(--r-5); overflow: hidden; }
.doc-group + .doc-group { margin-top: var(--sp-4); }
.doc-group-head {
  display: flex; align-items: center; gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-7); background: var(--bg);
  border: 0; width: 100%; text-align: left;
  cursor: pointer; font-family: inherit;
  border-bottom: 1px solid transparent;
  transition: background var(--dur-1);
}
.doc-group-head:hover { background: var(--line-2); }
.doc-group.is-open .doc-group-head { border-bottom-color: var(--line-2); }
.doc-group-head .folder-ic {
  width: 24px; height: 24px; border-radius: var(--r-3);
  background: var(--primary-50); color: var(--primary);
  display: grid; place-items: center; flex: 0 0 auto;
}
.doc-group-head .name {
  font-size: var(--fs-135); font-weight: 600; color: var(--ink); flex: 1;
}
.doc-group-head .count {
  font-size: var(--fs-12); color: var(--muted);
  background: #fff; padding: 1px 7px; border-radius: 8px; font-weight: 600;
  font-feature-settings: "tnum"; border: 1px solid var(--line);
}
.doc-group-head .chev { color: var(--soft); transition: transform var(--dur-2); }
.doc-group.is-open .doc-group-head .chev { transform: rotate(90deg); }
.doc-group-body {
  padding: var(--sp-5) var(--sp-7); display: none; flex-direction: column; gap: var(--sp-4);
}
.doc-group.is-open .doc-group-body { display: flex; }
.doc-group-body .file-row { background: #fff; }

/* -----------------------------------------------------------
   Property accordion (§ 10.11) — collapsible read-only property
   rows on the EditClientOrder + ViewClientOrderStatus "Properties"
   tabs. Mirrors the .doc-group interaction (closed-by-default,
   chevron rotate, .is-open body toggle); differs in the head label
   (single-line address, no count badge) and the body (address field
   grid + per-section field groups, gap 16px).
   ----------------------------------------------------------- */
.prop-acc { border: 1px solid var(--line-2); border-radius: var(--r-5); overflow: hidden; }
.prop-acc + .prop-acc { margin-top: var(--sp-4); }
.prop-acc-head {
  display: flex; align-items: center; gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-7); background: var(--bg);
  border: 0; width: 100%; text-align: left;
  cursor: pointer; font-family: inherit;
  border-bottom: 1px solid transparent;
  transition: background var(--dur-1);
}
.prop-acc-head:hover { background: var(--line-2); }
.prop-acc.is-open .prop-acc-head { border-bottom-color: var(--line-2); }
.prop-acc-head .geo-ic {
  width: 24px; height: 24px; border-radius: var(--r-3);
  background: var(--primary-50); color: var(--primary);
  display: grid; place-items: center; flex: 0 0 auto;
}
.prop-acc-head .name {
  font-size: var(--fs-135); font-weight: 600; color: var(--ink); flex: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.prop-acc-head .chev { color: var(--soft); transition: transform var(--dur-2); flex: 0 0 auto; }
.prop-acc.is-open .prop-acc-head .chev { transform: rotate(90deg); }
.prop-acc-body { padding: var(--sp-7); display: none; flex-direction: column; gap: var(--sp-8); }
.prop-acc.is-open .prop-acc-body { display: flex; }

/* -----------------------------------------------------------
   Code block (§ 10.6) — used by ApiDocumentation
   ----------------------------------------------------------- */
.code-block {
  position: relative; border: 1px solid var(--line);
  border-radius: var(--r-5); overflow: hidden; margin-bottom: 12px;
  background: #fff;
}
.code-block-head {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg); padding: 6px 12px;
  border-bottom: 1px solid var(--line-2);
}
.code-block-lang {
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  color: var(--muted); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
}
.code-block-copy {
  margin-left: auto; background: transparent; border: 1px solid var(--line);
  border-radius: var(--r-3); padding: 3px 9px;
  font-size: 12px; color: var(--ink-2); cursor: pointer; font-family: inherit;
  transition: all var(--dur-1);
}
.code-block-copy:hover { background: #fff; border-color: var(--ink-2); }
.code-block pre {
  margin: 0; padding: 14px; overflow-x: auto;
  font-family: var(--font-mono); font-size: 13px; line-height: 1.55;
  color: var(--ink-2); background: #fff;
}
.code-block code { font-family: inherit; font-size: inherit; color: inherit; }

/* -----------------------------------------------------------
   Callout (§ 10.7) — debug zones, info/warning notes
   ----------------------------------------------------------- */
.callout {
  border-radius: var(--r-6); padding: 16px 18px;
  border: 2px dashed var(--line); margin: 14px 0;
}
.callout-head {
  display: flex; align-items: center; gap: 10px; margin-bottom: 10px;
}
.callout-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-3);
  font-size: 11.5px; font-weight: 700;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.callout--debug {
  border-color: var(--warning-dark);
  background: repeating-linear-gradient(
    45deg,
    rgba(202,138,4,.025), rgba(202,138,4,.025) 12px,
    transparent 12px, transparent 24px
  );
}
.callout--debug .callout-chip { background: var(--warning-dark); color: #fff; }
.callout--info {
  border-style: solid; border-color: var(--primary);
  background: var(--primary-50);
}
.callout--info .callout-chip { background: var(--primary); color: #fff; }

/* -----------------------------------------------------------
   HTTP method badge (used by ApiDocumentation)
   ----------------------------------------------------------- */
.method-badge {
  display: inline-block; padding: 3px 10px; border-radius: var(--r-3);
  font-weight: 700; font-size: 12px; color: #fff; margin-right: 8px;
  font-family: var(--font-mono); letter-spacing: 0.04em;
}
.method-badge.method-get   { background: var(--method-get); }
.method-badge.method-post  { background: var(--method-post); }
.method-badge.method-patch { background: var(--method-patch); }
.method-badge.method-debug { background: var(--method-debug); }

.endpoint-bar {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg); padding: 10px 14px;
  border-radius: var(--r-4); margin-bottom: 14px;
  border: 1px solid var(--line-2);
}
.endpoint-path {
  font-family: var(--font-mono); font-size: var(--fs-14); font-weight: 600;
  color: var(--ink);
}

/* -----------------------------------------------------------
   Form-validation reskin (§ 11.3) — Blazor's <ValidationMessage>
   ----------------------------------------------------------- */
.validation-message {
  display: flex; align-items: center; gap: 4px;
  font-size: 12px; color: var(--error); margin-top: 2px;
}

/* Segmented radio (§ 11.6) */
.seg {
  display: inline-flex; background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--r-5);
  padding: 3px; gap: 2px; width: 100%;
}
.seg label {
  flex: 1; text-align: center; padding: 6px 10px;
  border-radius: var(--r-3); font-size: 13px; font-weight: 600;
  color: var(--muted); cursor: pointer; transition: all var(--dur-1);
}
.seg input { display: none; }
.seg label:hover { color: var(--ink); }
.seg input:checked + label, .seg label.is-on {
  background: #fff; color: var(--ink); box-shadow: var(--shadow-1);
}
.seg.seg--error { box-shadow: 0 0 0 2px rgba(239,68,68,.35); }

/* -----------------------------------------------------------
   Status radio (§ 11.8) — diligence status-preset input.
   Square one-glyph radio buttons for the standard five-value
   status vocabulary (DiligenceStatusPresets). Inputs stay
   focusable (visually hidden, not display:none) so native
   radio keyboard navigation works.
   ----------------------------------------------------------- */
.status-radio-group {
  position: relative; /* containing block for the hidden inputs — without it they resolve
                         against the document, escape the pane's scroll clip, stretch the
                         page height, and label-click focus scrolls to the page bottom */
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
}
.status-radio-group input {
  position: absolute; top: 0; left: 0; width: 1px; height: 1px;
  opacity: 0; margin: 0; pointer-events: none;
}
.status-radio {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--r-3);
  border: 1px solid var(--line);
  font-size: var(--fs-12); font-weight: 700; line-height: 1;
  cursor: pointer; user-select: none;
  transition: all var(--dur-1);
}
.status-radio i { font-size: 13px; }

/* Unchecked: soft tint + colored glyph. */
.status-radio--passed    { background: var(--success-soft); color: var(--success); }
.status-radio--agent     { background: var(--warning-soft); color: var(--warning-dark); }
.status-radio--lender    { background: var(--primary-50);   color: var(--primary); }
.status-radio--escalated { background: var(--error-soft);   color: var(--error); }
.status-radio--waived    { background: var(--violet-soft);  color: var(--violet); }

.status-radio--passed:hover    { border-color: var(--success); }
.status-radio--agent:hover     { border-color: var(--warning-dark); }
.status-radio--lender:hover    { border-color: var(--primary); }
.status-radio--escalated:hover { border-color: var(--error); }
.status-radio--waived:hover    { border-color: var(--violet); }

/* Checked (or .is-solid for static legend chips): solid fill, white glyph. */
.status-radio-group input:checked + .status-radio--passed,    .status-radio--passed.is-solid    { background: var(--success);      border-color: var(--success);      color: #fff; }
.status-radio-group input:checked + .status-radio--agent,     .status-radio--agent.is-solid     { background: var(--warning-dark); border-color: var(--warning-dark); color: #fff; }
.status-radio-group input:checked + .status-radio--lender,    .status-radio--lender.is-solid    { background: var(--primary);      border-color: var(--primary);      color: #fff; }
.status-radio-group input:checked + .status-radio--escalated, .status-radio--escalated.is-solid { background: var(--error);        border-color: var(--error);        color: #fff; }
.status-radio-group input:checked + .status-radio--waived,    .status-radio--waived.is-solid    { background: var(--violet);       border-color: var(--violet);       color: #fff; }

/* Generic (non-preset) option sets on a radio-typed field: neutral text buttons. */
.status-radio--text {
  width: auto; min-width: 28px; padding: 0 10px;
  background: var(--card); color: var(--ink-2);
  font-weight: 600; font-size: var(--fs-125);
}
.status-radio--text:hover { border-color: var(--soft); }
.status-radio-group input:checked + .status-radio--text {
  background: var(--primary); border-color: var(--primary); color: #fff;
}

.status-radio-group input:focus-visible + .status-radio { box-shadow: var(--ring-primary); }
.status-radio-group input:disabled + .status-radio {
  cursor: not-allowed; opacity: .55; border-color: var(--line);
}

/* Static (non-input) chips — the legend and read-only contexts. */
.status-radio.is-static { cursor: default; }
.status-radio--sm { width: 20px; height: 20px; font-size: 10px; border-radius: var(--r-2); }
.status-radio--sm i { font-size: 11px; }

/* Status key — the legend explaining the glyphs (renders once above the fields). */
.status-key {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  padding: 8px 12px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-5);
}
.status-key__title {
  font-size: var(--fs-11); font-weight: 700; color: var(--soft);
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
}
.status-key__item {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-12); font-weight: 600; color: var(--ink-2); white-space: nowrap;
}

/* -----------------------------------------------------------
   Live indicator pill (small dot + label)
   ----------------------------------------------------------- */
.live-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 9px; border-radius: var(--r-pill);
  background: var(--gray-soft); color: #4b5563;
  font-size: 12px; font-weight: 600;
}
.live-pill::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--success);
}

/* -----------------------------------------------------------
   Data states (§ 13)
   ----------------------------------------------------------- */
/* Skeleton */
.sk {
  display: inline-block; height: 12px; border-radius: 4px;
  background: linear-gradient(90deg, var(--line) 0%, var(--line-2) 50%, var(--line) 100%);
  background-size: 200% 100%;
  animation: tk-shimmer 1.4s ease-in-out infinite;
}
.sk-text  { width: 80%; }
.sk-pill  { width: 64px; height: 18px; border-radius: var(--r-pill); }
.sk-block { display: block; height: 14px; border-radius: 6px; }
.sk-card  { display: block; width: 100%; height: 90px; border-radius: var(--r-6); }
.sk-row   { display: block; width: 100%; height: 48px; border-radius: var(--r-4); }
.sk-circle{ display: inline-block; border-radius: 50%; width: 24px; height: 24px; }

@keyframes tk-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Spinner (full-page loading) */
.state-loading {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 56px 20px; color: var(--muted); font-size: var(--fs-135);
}
.spinner {
  width: 18px; height: 18px;
  border: 2px solid var(--line); border-top-color: var(--primary);
  border-radius: 50%; animation: tk-spin 0.7s linear infinite;
}
@keyframes tk-spin { to { transform: rotate(360deg); } }

/* Empty state */
.state-empty        { padding: 56px 20px; text-align: center; }
.state-empty-ic     {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--bg); color: var(--muted);
  display: grid; place-items: center; margin: 0 auto 14px;
}
.state-empty-ic i   { font-size: 19px; }
.state-empty-title  { font-size: var(--fs-15); font-weight: 700; color: var(--ink); margin-bottom: 4px; }
.state-empty-sub    { font-size: 13.5px; color: var(--muted); }
.state-empty-actions{ margin-top: 14px; display: flex; gap: 8px; justify-content: center; }

/* Error state */
.state-error        { padding: 56px 20px; text-align: center; }
.state-error-ic     {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--error-soft); color: var(--error);
  display: grid; place-items: center; margin: 0 auto 14px;
}
.state-error-ic i   { font-size: 22px; }
.state-error-title  { font-size: var(--fs-15); font-weight: 700; color: var(--ink); margin-bottom: 4px; }
.state-error-sub    { font-size: 13.5px; color: var(--muted); max-width: 360px; margin: 0 auto; }
.state-error-actions{ margin-top: 14px; display: flex; gap: 8px; justify-content: center; }

/* Success state (inline within forms) */
.state-success {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border-radius: var(--r-4);
  background: var(--success-soft); color: #0a9558;
  font-size: var(--fs-135); font-weight: 600;
}
.state-success i { font-size: 15px; }

/* Inline alert (replaces RadzenAlert) */
.alert {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--r-5);
  font-size: var(--fs-135); border: 1px solid var(--line);
  background: #fff;
}
.alert i { font-size: 17px; flex: 0 0 auto; margin-top: 1px; }
.alert--error   { background: var(--error-soft);   border-color: rgba(239,68,68,.2); color: var(--error); }
.alert--success { background: var(--success-soft); border-color: rgba(15,169,104,.2); color: #0a9558; }
.alert--warning { background: var(--warning-soft); border-color: rgba(234,179,8,.2);  color: var(--warning-dark); }
.alert--info    { background: var(--primary-50);   border-color: rgba(1,30,92,.15);   color: var(--primary); }

/* -----------------------------------------------------------
   Pop animation (§ 5)
   ----------------------------------------------------------- */
@keyframes tk-pop {
  0%   { transform: scale(.6); }
  60%  { transform: scale(1.15); }
  100% { transform: scale(1); }
}
.tk-pop { animation: tk-pop .28s ease both; }

/* -----------------------------------------------------------
   Inline alert — replaces RadzenAlert. Used for compact,
   in-page status messages (server errors on pre-auth, save
   feedback on admin CRUD). Distinct from .state-error /
   .state-empty (which are full empty-data blocks). Add with
   one of the modifier classes; never bare .alert.
   ----------------------------------------------------------- */
.alert {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 10px 12px; border-radius: var(--r-5);
  font-size: var(--fs-135); border: 1px solid;
  line-height: var(--lh-snug);
}
.alert i { flex: 0 0 auto; font-size: 15px; margin-top: 1px; }
.alert > .alert-body { flex: 1; min-width: 0; }
.alert .alert-title { font-weight: 700; }
.alert--error   { background: var(--error-soft);   color: var(--error);       border-color: rgba(239,68,68,.25); }
.alert--info    { background: var(--primary-50);   color: var(--primary);     border-color: rgba(1,30,92,.15); }
.alert--warning { background: var(--warning-soft); color: var(--warning-dark);border-color: rgba(202,138,4,.25); }
.alert--success { background: var(--success-soft); color: #0a9558;            border-color: rgba(15,169,104,.25); }

/* Text-link button — for button-like inline links inside auth /
   admin chrome (e.g. "Forgot password?"). Doesn't carry the
   button chrome but is keyboard-focusable and follows .btn focus rules. */
.text-link {
  background: transparent; border: 0; padding: 0;
  color: var(--primary); font-weight: 600; font-size: var(--fs-135);
  cursor: pointer; font-family: inherit;
}
.text-link:hover { text-decoration: underline; }
.text-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-2); }

/* -----------------------------------------------------------
   Auth shell — pre-auth pages (Login, ResetPassword as dialog,
   SecurityCode, RegisterApplicationUser as dialog, Unauthorized).
   Used by Components/Layout/LoginLayout.razor. The shell is
   purpose-built for unauthenticated surfaces and intentionally
   different from the .app sidebar+topbar shell — there is no
   sidebar, the page is centered, and the brand is rendered as
   a vertical lockup above the auth card.
   ----------------------------------------------------------- */
.auth-shell {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 40px 20px;
  background: var(--bg);
  background-image:
    radial-gradient(1200px 600px at 50% -200px, rgba(1,30,92,0.06), transparent 60%);
}
.auth-stack {
  width: 100%; max-width: 480px;
  display: flex; flex-direction: column; align-items: stretch; gap: 24px;
}
.auth-brand {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  margin-bottom: 0;
}
.auth-brand-img { width: 88px; height: 88px; object-fit: contain; }
.auth-brand-name {
  font-size: 26px; font-weight: 700; color: var(--ink);
  letter-spacing: var(--tracking-title);
}
.auth-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-7); padding: 36px;
  display: flex; flex-direction: column; gap: 20px;
  box-shadow: var(--shadow-2);
}
.auth-title {
  font-size: 19px; font-weight: 700; color: var(--ink);
  margin: 0; letter-spacing: -0.01em;
}
.auth-sub { font-size: var(--fs-145); color: var(--muted); margin: 0; }
.auth-form { display: flex; flex-direction: column; gap: 16px; }
.auth-actions {
  display: flex; flex-direction: column; gap: 8px; margin-top: 8px;
}
.auth-actions .btn { justify-content: center; }
.auth-foot {
  text-align: center; font-size: var(--fs-135); color: var(--muted);
}
.auth-foot a { color: var(--primary); font-weight: 600; text-decoration: none; }
.auth-foot a:hover { text-decoration: underline; }
.auth-link-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; font-size: 13px;
}
.auth-link-row a { color: var(--primary); font-weight: 600; text-decoration: none; }
.auth-link-row a:hover { text-decoration: underline; }

/* Dialog-form variant: when ResetPassword / RegisterApplicationUser
   render INSIDE a Radzen dialog (DialogService.OpenAsync), they don't
   want the auth-shell chrome — just the form. .auth-form-stack groups
   the fields + the right-aligned action row. */
.auth-form-stack {
  display: flex; flex-direction: column; gap: 12px; min-width: 360px;
}
.auth-form-stack .form-row-end {
  display: flex; gap: 8px; justify-content: flex-end; margin-top: 6px;
}

/* SecurityCode: reskin RadzenSecurityCode boxes via radzen-overrides;
   here we just provide the centered grouping wrapper. */
.auth-code-row {
  display: flex; justify-content: center; padding: 4px 0 8px;
}

/* -----------------------------------------------------------
   Title Agent portal shell — pages that use EmptyLayout
   (TitleAgent dashboard, TitleAgent order page). External
   agent surfaces don't share the FS staff sidebar; they get
   a self-contained brand topbar instead.
   ----------------------------------------------------------- */
.portal-shell {
  min-height: 100vh; display: flex; flex-direction: column;
  background: var(--bg);
}
.portal-topbar {
  height: var(--layout-topbar); padding: 0;
  border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,.85); backdrop-filter: blur(8px);
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: stretch;
}
/* Inner row — reuses .portal-content so the topbar's elements align
   column-for-column with the body content underneath (Bootstrap-container
   style). No vertical padding; the bar's own height controls that. */
.portal-topbar > .portal-content {
  padding-top: 0; padding-bottom: 0;
  display: flex; align-items: center; gap: 16px;
  flex: 1;
}
.portal-brand { display: flex; align-items: center; gap: 10px; }
.portal-brand .brand-text {
  display: flex; flex-direction: column; line-height: var(--lh-tight);
}
.portal-brand .brand-name {
  font-size: var(--fs-15); font-weight: 700; color: var(--ink);
  letter-spacing: -0.01em;
}
.portal-brand .brand-tag {
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--soft); margin-top: 1px;
}
.portal-user {
  margin-left: auto;
  display: inline-flex; flex-direction: column; align-items: flex-end;
  line-height: 1.2; text-align: right; min-width: 0;
}
.portal-user .name {
  color: var(--ink); font-weight: 600; font-size: var(--fs-135);
  max-width: 240px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.portal-user .meta {
  color: var(--muted); font-size: 12px;
  max-width: 240px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
@media (max-width: 720px) { .portal-user { display: none; } }
.portal-actions { display: flex; align-items: center; gap: 8px; }
.portal-content {
  width: 100%; max-width: 920px; margin: 0 auto;
  padding: var(--layout-content-pad-y) var(--layout-content-pad-x) 40px;
  flex: 1;
}
.portal-content--wide { max-width: 1180px; }

/* Chat-style message thread (used in TitleAgent order page).
   Two alignments — incoming (left, neutral) and outgoing (right, primary tint). */
.msg-thread {
  display: flex; flex-direction: column; gap: var(--sp-4);
  max-height: 360px; overflow-y: auto; padding: 4px;
}
.msg-row { display: flex; }
.msg-row--out { justify-content: flex-end; }
.msg-bubble {
  max-width: 75%;
  padding: 8px 12px;
  border-radius: var(--r-6);
  font-size: var(--fs-135); color: var(--ink-2);
  background: var(--bg); border: 1px solid var(--line-2);
  line-height: var(--lh-snug);
}
.msg-row--out .msg-bubble {
  background: var(--primary-50); border-color: rgba(1,30,92,.10);
}
.msg-meta {
  font-size: 11px; color: var(--soft); margin-bottom: 3px;
  font-feature-settings: "tnum";
}
.msg-bubble strong.msg-author { color: var(--ink); font-weight: 600; }

/* -----------------------------------------------------------
   Focus rings (§ 14.2)
   ----------------------------------------------------------- */
.btn:focus-visible,
.icon-btn:focus-visible,
.nav-item:focus-visible,
.chip:focus-visible,
.row-icon-btn:focus-visible,
.tab:focus-visible,
.profile-trigger:focus-visible,
.profile-item:focus-visible,
.cl-item:focus-visible,
.page-btn:focus-visible,
.doc-group-head:focus-visible,
.prop-acc-head:focus-visible,
/* A clickable .file-row is a role="button" with tabindex="0" (the copy-source pickers), so it needs the
   same ring every other interactive element gets. The inert .file-row--disabled variant never gets one —
   it is tabindex="-1" and is never combined with .is-clickable. */
.file-row.is-clickable:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* -----------------------------------------------------------
   Reduced motion (§ 5 — mandatory)
   ----------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* -----------------------------------------------------------
   Multi-party messaging (§ 10.11 .chat-pane, § 10.12 .msg)
   New cross-page primitives for the conversation surface.
   ----------------------------------------------------------- */

/* Chat pane shell — works in three host contexts:
     1. Drawer body (flex parent): fills via flex: 1; height: 100%
     2. Inline tab content (no explicit height): falls back to min/max height
     3. Inline pane sibling (fixed-width column): fills via height: 100%
   The grid uses grid-template-rows: 1fr so the conversation viewport stretches
   vertically rather than collapsing to its (empty initial) content height.
   The list column is PROPORTIONAL, not fixed: 40% still resolves to the full 240px
   cap on the ~611-618px panes at 1920, and floors the ~496px lender pane at 1600 to
   ~198px so a narrow host gives the messages the room instead. No @media needed —
   clamp() reads the pane's own width, which is what actually varies here. */
.chat-pane {
  display: grid;
  grid-template-columns: clamp(184px, 40%, 240px) 1fr;
  grid-template-rows: 1fr;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-6); overflow: hidden;
  min-height: 480px;
  max-height: calc(100vh - 160px);
  height: 100%;
  width: 100%;
  flex: 1 1 auto;
}
/* Stacked mode (narrow sticky panels, e.g. the title-agent order page) keeps the
   conversation LIST — so party badges render there too — but stacks it ABOVE the
   viewport as a capped, internally-scrolling strip instead of a side column.
   Solo mode shows no list (single-conversation host; the chat head shows the title). */
.chat-pane--stacked { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
.chat-pane--solo    { grid-template-columns: 1fr; }
.chat-pane--stacked .chat-list {
  border-right: none; border-bottom: 1px solid var(--line-2);
  /* Proportional cap so the list never dominates a short / mobile pane; floors at 120px
     and tops out at 240px. Pairs with .chat-list-scroll's overflow so overflow rows scroll. */
  max-height: clamp(120px, 30vh, 240px); min-height: 0;
}
.chat-pane--solo .chat-list { display: none; }
/* When hosted inside a drawer-body the drawer itself supplies the height —
   drop the min-height so a short viewport doesn't push the composer off-screen. */
.drawer-body > .chat-pane { min-height: 0; max-height: none; }

.chat-list {
  border-right: 1px solid var(--line-2);
  display: flex; flex-direction: column; min-width: 0;
  background: var(--card); overflow: hidden;
}
.chat-list-head {
  padding: var(--sp-5) var(--sp-6);
  border-bottom: 1px solid var(--line-2);
  display: flex; align-items: center; gap: var(--sp-3);
  flex-shrink: 0;
  background: var(--card);
}
.chat-list-head .input { font-size: var(--fs-125); padding: var(--sp-3) var(--sp-4); }
.chat-list-search { flex: 1; min-width: 0; }
/* Make the rows the scrollable region so the search input stays pinned. */
.chat-list > .chat-list-item:first-of-type,
.chat-list > .chat-list-scroll { flex: 1 1 auto; }
/* The rows actually scroll within the (capped, in stacked mode) list height — without this
   overflow-y the stacked list clips conversations past its cap with no way to reach them. */
.chat-list-scroll { min-height: 0; overflow-y: auto; }
.chat-list-empty {
  padding: var(--sp-12) var(--sp-8);
  color: var(--soft); font-size: var(--fs-125);
  text-align: center;
}

.chat-list-item {
  /* Reset native <button> chrome so the row blends into the design system. */
  appearance: none; -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-radius: 0;
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  text-align: left;
  width: 100%;

  display: flex; align-items: center; gap: var(--sp-5);
  padding: var(--sp-6) var(--sp-7) var(--sp-6) var(--sp-6);
  cursor: pointer;
  position: relative;
  transition: background var(--dur-1) var(--ease);
}
/* Subtle hairline between rows, with the first row flush against the list head. */
.chat-list-item + .chat-list-item { box-shadow: inset 0 1px 0 var(--line-2); }
.chat-list-item:hover { background: var(--bg); }
.chat-list-item.is-active { background: var(--primary-50); }
/* Left accent stripe on the active row — design-system pattern for vertical
   list selection (mirrors .nav-item.is-active). The pseudo-element keeps the
   inset-shadow hairlines above clean. */
.chat-list-item.is-active::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px; background: var(--primary); border-radius: 0 2px 2px 0;
}
.chat-list-item-body { min-width: 0; flex: 1; }
/* flex-start, not baseline: the pills may wrap to a second line and the timestamp must
   stay pinned to the FIRST one. */
.chat-list-item-row { display: flex; align-items: flex-start; gap: var(--sp-3); }
/* Line 1 of a row. The pills are ALL of it: one per party the viewer is talking TO (their
   own party is dropped; an observer row shows every party since "own party" has no meaning
   there). Source: ConversationSummary.PartySet → Models.TenantKindNames, filtered by
   ChatPane.RowParties. No participant names and no custom title on this line — those moved
   to the chat head's .chat-head-sub. See the .party-tag primitive below. */
.chat-list-item-parties {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  flex: 1; min-width: 0;
}
/* The line-1 fallback label, and ONLY that: rendered in place of the pills when the
   conversation has no current parties (an all-departed thread an FS observer can still
   see), so the line is never blank. Every row that has parties renders pills instead, so
   no state may hang off this selector alone; see the .is-active / .has-unread /
   .is-observer rules below. */
.chat-list-item-name {
  font-size: var(--fs-125); font-weight: 500; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* 40px basis: shrink-with-ellipsis on the pill line first; wrap under the pills only when
     fewer than 40px remain (a 3-party fallback row on the 184px track). */
  flex: 1 1 40px; min-width: 0;
}
.chat-list-item-time {
  font-size: 11px; color: var(--soft);
  /* Matches the rendered .party-tag--xs pill box (measured 16px in Chrome: the 11px inline-flex
     pill's own line box + 2 × 1px border) so the timestamp optically centres on the first pill
     row under the flex-start alignment above. */
  line-height: 16px;
  font-feature-settings: "tnum"; flex-shrink: 0;
}
/* Line 2 of a row: the last message, prefixed with its sender's first name. */
.chat-list-item-preview {
  font-size: var(--fs-125); color: var(--muted); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The space after the colon is a real text node (@(" ") in the razor — Blazor drops whitespace-only
   literals between an element and an expression), so copy/paste and screen readers get it too. */
.chat-list-item-sender { font-weight: 600; color: var(--ink-2); }
/* Active row: name (when present) and timestamp both take the primary tint. */
.chat-list-item.is-active .chat-list-item-name,
.chat-list-item.is-active .chat-list-item-time { color: var(--primary); }
.chat-list-item.is-active .chat-list-item-name { font-weight: 600; }
/* Unread row: the name darkens, and so does the preview line — which is the part that
   always renders, and the part an unread row is actually about. */
.chat-list-item.has-unread .chat-list-item-name { font-weight: 700; color: var(--ink); }
.chat-list-item.has-unread .chat-list-item-preview,
.chat-list-item.has-unread .chat-list-item-sender { color: var(--ink); font-weight: 600; }

/* ── Party tag ──────────────────────────────────────────────────────────
   Identity pill naming a conversation party (FundingShield / Lender / Title
   Agent). A distinct axis from the closed five-state status .badge — do not
   merge the two. Shared by the chat conversation list and the View Members
   dialog. The colour suffix (fs/lender/ta) comes from Models.TenantKindNames.Slug();
   never hard-code the party names. */
.party-tag {
  display: inline-flex; align-items: center;
  font-size: var(--fs-11); font-weight: 600;
  padding: 1px var(--sp-3); border-radius: var(--r-pill);
  border: 1px solid var(--line-2); background: var(--bg);
  color: var(--ink-2); white-space: nowrap;
}
.party-tag--fs     { color: var(--primary); border-color: var(--primary); background: var(--primary-50); }
.party-tag--lender { color: var(--ink); }
.party-tag--ta     { color: var(--ink-2); }
/* Compact variant for dense rows (the chat-list row, where the pills lead line 1) — tighter padding only;
   font stays on the --fs-11 scale floor. */
.party-tag--xs { padding: 0 var(--sp-2); }

/* Observer row (FS god-view): mute BOTH text lines, not just the conditional name span.
   Ordered after .has-unread so it wins on equal specificity. */
.chat-list-item.is-observer .chat-list-item-name,
.chat-list-item.is-observer .chat-list-item-preview,
.chat-list-item.is-observer .chat-list-item-sender { color: var(--muted); font-weight: 500; }
.chat-list-item-observer-ic { color: var(--soft); margin-right: var(--sp-2); line-height: 16px; }
/* Trailing unread badge — tightens to the row end so the row reads cleanly. */
.chat-list-item > .badge { flex-shrink: 0; align-self: center; }
/* Focus-visible ring — uses an inset version so it doesn't get cropped by the
   list's overflow: hidden. */
.chat-list-item:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--primary);
}

/* Chat viewport — flex column so the message body can take all remaining space
   between the header and the composer footer. */
.chat-view { display: flex; flex-direction: column; min-width: 0; min-height: 0; height: 100%; background: var(--card); overflow: hidden; }
.chat-head {
  display: flex; align-items: center; gap: var(--sp-6);
  padding: var(--sp-6) var(--sp-8); border-bottom: 1px solid var(--line-2);
  background: var(--card);
}
/* min-width: 0 is load-bearing — without it this flex child refuses to shrink and
   .chat-head-sub can never ellipsize. */
.chat-head-titles { min-width: 0; flex: 1; }
/* Font rules apply to the "Conversation" fallback span; when parties exist this box holds
   .party-tag pills instead, which carry their own type scale. Deliberately no
   white-space/overflow/text-overflow here: the pills must be allowed to wrap. */
.chat-head-title { font-size: var(--fs-145); font-weight: 600; color: var(--ink); }
/* The head's large text is the same party pills the list row leads with (ChatPane.RowParties),
   at regular .party-tag size rather than --xs. */
.chat-head-parties { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
/* Custom title (when set) · the current participants' display names. */
.chat-head-sub {
  font-size: var(--fs-125); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-head-actions { display: flex; gap: var(--sp-2); align-items: center; }
.chat-head-avatars { display: inline-flex; }
.chat-head-avatars .avatar { margin-left: -10px; border: 2px solid var(--card); }
.chat-head-avatars .avatar:first-child { margin-left: 0; }
.chat-body {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: var(--sp-6) var(--sp-8); background: var(--bg);
  display: flex; flex-direction: column; gap: var(--sp-4);
}

.chat-composer {
  padding: var(--sp-6) var(--sp-8); border-top: 1px solid var(--line-2);
  background: var(--card); display: flex; flex-direction: column; gap: var(--sp-3);
}
.chat-composer-attachments { display: flex; flex-direction: column; gap: var(--sp-2); }
.chat-composer-actions { display: flex; align-items: center; gap: var(--sp-3); }
.chat-composer-actions > .input { flex: 1; resize: vertical; min-height: 38px; max-height: 160px; }
.chat-composer-spacer { flex: 1; }
.chat-composer-observer {
  padding: var(--sp-4) var(--sp-8); font-size: var(--fs-125); color: var(--muted);
  background: var(--bg); border-top: 1px solid var(--line-2); text-align: center;
}

/* Message bubble (replaces .msg-bubble for the new system) */
.msg {
  display: flex; gap: var(--sp-4); align-items: flex-start;
}
.msg--out { flex-direction: row-reverse; }
.msg-avatar { flex-shrink: 0; }
.msg--out .msg-avatar { display: none; }
.msg-stack { display: flex; flex-direction: column; max-width: min(560px, 80%); gap: var(--sp-1); }
.msg--out .msg-stack { align-items: flex-end; }
.msg-meta-line {
  font-size: 11px; color: var(--soft);
  font-feature-settings: "tnum"; display: inline-flex; gap: var(--sp-3); align-items: baseline;
}
.msg-author { color: var(--ink); font-weight: 600; }
.msg-time {}
.msg-edited { font-style: italic; }
/* Hat caption — small muted tag (e.g. "FundingShield", "Lender", "Title Agent")
   shown after the time so any participant can tell which party the speaker
   represents in a multi-party conversation. Uses --muted (a notch above the
   timestamp's --soft) and a leading dot so it reads as a separate field. */
.msg-party {
  color: var(--muted);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
}
.msg-party::before { content: "·"; margin-right: var(--sp-2); color: var(--soft); }

/* ── Chat rail collapse strip ───────────────────────────────────────────
   Thin vertical button shown when a persistent chat rail is collapsed.
   Click to re-expand. Lives next to the main content column on lender +
   FS edit pages. Full button reset to neutralize browser defaults
   (background, border, font, padding). */
.chat-rail-strip {
  appearance: none; -webkit-appearance: none;
  font-family: inherit; font-size: inherit; color: var(--ink-2);
  cursor: pointer;
  width: 44px;
  height: 100%;
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-4);
  padding: 14px 6px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-6);
  box-shadow: var(--shadow-1);
  transition: background var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
}
.chat-rail-strip:hover {
  background: var(--bg);
  border-color: var(--primary);
  color: var(--primary);
}
.chat-rail-strip:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--primary);
}
.chat-rail-strip-ic { font-size: 18px; line-height: 1; }
.chat-rail-strip-count {
  font-size: var(--fs-11); font-weight: 700;
  min-width: 18px; padding: 0 5px; line-height: 16px;
  border-radius: 999px;
  background: var(--primary); color: #fff;
  text-align: center;
}
.chat-rail-strip-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  margin-top: auto;
  font-size: var(--fs-125);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  text-transform: uppercase;
}
.chat-rail-strip:hover .chat-rail-strip-label { color: var(--primary); }

/* Collapse handle floated on the inside-left edge of an expanded rail.
   Click to re-collapse to the strip. Uses .icon-btn so it picks up the
   standard styling, but is absolutely positioned by its parent. */
.chat-rail-collapse-handle {
  position: absolute;
  top: 10px;
  left: -14px;
  z-index: 2;
  background: var(--card);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-1);
}

/* ── Loading skeletons (mirror the .sk shimmer system in §13) ─────────────
   Used while GetConversationsForOrderAsync / GetMessagesAsync are in flight.
   The shapes match the real markup they replace so there is no layout jump
   when the data lands. */
.chat-list-sk-row {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-7) var(--sp-6) var(--sp-6);
}
.chat-list-sk-row + .chat-list-sk-row { box-shadow: inset 0 1px 0 var(--line-2); }
/* Line 1 of the real row now leads with .party-tag--xs pills, so the skeleton's first
   bar is pill-shaped and pill-height (16px, as rendered) to match. Its WIDTH comes from the inline
   style in ChatPane.razor (varied per row) and is deliberately left there. */
.chat-list-sk-name    { height: 16px; border-radius: var(--r-pill); }
.chat-list-sk-preview { height: 10px; opacity: 0.7; }

.chat-body-sk {
  display: flex; flex-direction: column; gap: var(--sp-5);
  padding: var(--sp-6); width: 100%;
}
.msg--sk { opacity: 0.85; }
.msg--sk .msg-body-sk { height: 36px; border-radius: var(--r-6); display: block; max-width: 100%; }
.msg-body {
  padding: var(--sp-5) var(--sp-7);
  background: var(--card); border: 1px solid var(--line-2);
  border-radius: var(--r-6); color: var(--ink-2);
  font-size: var(--fs-14); line-height: var(--lh-snug);
  white-space: pre-wrap; word-break: break-word;
}
.msg--out .msg-body {
  background: var(--primary-50);
  border-color: rgba(1,30,92,.10);
}
.msg--same-author .msg-meta-line { display: none; }

.msg-attach {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  background: var(--card); border: 1px solid var(--line-2);
  border-radius: var(--r-4); cursor: pointer;
  font-size: var(--fs-125); color: var(--ink-2); text-decoration: none;
  transition: border-color var(--dur-1) var(--ease);
}
.msg-attach:hover { border-color: var(--primary); }
.msg-attach-name { font-weight: 500; }
.msg-attach-type { color: var(--soft); font-size: 11px; margin-left: var(--sp-2); }

.msg-actions {
  display: none; gap: var(--sp-1); margin-top: var(--sp-1);
}
.msg:hover .msg-actions { display: inline-flex; }
.msg--out .msg-actions { justify-content: flex-end; }

.msg--tombstone .msg-body {
  background: transparent; border: 1px dashed var(--line-2);
  font-style: italic; color: var(--soft);
}
.msg--pending .msg-body { opacity: 0.6; }
.msg--failed .msg-body { border-left: 2px solid var(--error); }

/* System events (joined / left / attachment-added) — centered single-line, no bubble */
.msg--system {
  justify-content: center;
}
.msg--system .msg-body {
  background: transparent; border: none; padding: var(--sp-2) 0;
  font-size: var(--fs-12); color: var(--soft);
  text-align: center; display: inline-flex; align-items: center; gap: var(--sp-2);
}
.msg--system .msg-avatar,
.msg--system .msg-meta-line,
.msg--system .msg-actions { display: none; }

/* Read receipts beneath outgoing bubbles */
.msg-receipts {
  font-size: 11px; color: var(--soft); margin-top: 2px;
  font-feature-settings: "tnum";
}

/* Presence dot on avatars */
.avatar-with-presence { position: relative; }
.chat-presence {
  position: absolute; bottom: 0; right: 0;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--success); border: 2px solid var(--card);
}

/* Avatar count chip (+N in stacked avatars) */
.avatar.avatar--count {
  background: var(--bg); color: var(--ink-2);
  font-size: 11px; font-weight: 600;
}

/* Unread count chip on icon buttons (extends the .nav-item .count recipe) */
.icon-btn { position: relative; }
.icon-btn .count {
  position: absolute; top: -2px; right: -2px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--primary); color: #fff;
  font-size: 10px; font-weight: 700;
  border-radius: var(--r-pill);
  font-feature-settings: "tnum";
  border: 2px solid var(--card);
}

/* Connection state indicator (extends .live-pill with an amber variant) */
.live-pill--warn::before { background: var(--warning); }

/* Drawer-over-drawer modifier — used when a document viewer needs to overlay
   the messages drawer on ViewClientOrderStatus. Bumps z-index to 52.
   Documented in § 4.4 of DESIGN.md. */
.drawer.drawer--over-drawer { z-index: 52; }

