/*
 * Copyright (c) 2026 BuildingLogiX. All rights reserved.
 *
 * StationCx. Proprietary and confidential. This source is licensed, not sold.
 * No part of it may be copied, distributed, disclosed or used to produce a
 * derivative work without the prior written permission of BuildingLogiX.
 *
 * Access to the hosted service under a current StationCx agreement does not
 * transfer any right in this source.
 */

/*
 * StationCx Cloud, UI mockup.
 *
 * Nav geometry and the card metaphor carry over from BuildingPane
 * (src/frontend/src/index.css). The color and the type are the BuildingLogiX
 * brand system: the five corporate colors, Barlow over Barlow Condensed,
 * IBM Plex Mono on every identifier, and the drafting grid under the whole
 * page so a screen reads like a sheet on a table rather than a web app.
 *
 * Token names did not move, only their values, so every rule in this file and
 * every color a view script hands a chart keeps working. Two rules the brand
 * is strict about, and the reason there are two orange tokens here:
 *
 *   --hi (#ed4723) is THE highlight. Never a surface, never body text. It
 *   marks the one thing a screen is about: demo data, a count that is only a
 *   floor, a party from outside the firm. Spend it once per screen.
 *
 *   --orange is warning STATE and nothing else. Amber means warn here, the
 *   way red means error and green means healthy.
 */
@import url("https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600;700&family=Barlow+Condensed:wght@500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap");

:root {
  color-scheme: light;

  /* the five corporate colors */
  --navy: #013b71;
  --blue: #326fb6;
  --sky: #69a2d4;
  --hi: #ed4723;
  --hi-soft: #fdeae4;

  /* surfaces. --ground is the drafting table; --bg-primary is a sheet laid
     on it, and every panel, table head and inset is one or the other.
     The two jobs came apart here. The deck's #f1f4f7 ground carries its own
     grid at print weight; on screen it read heavy behind full-bleed tables,
     so the ground goes light and the grid does the work of saying there is a
     table under the sheet. Lighten the grid with it and the sheet floats. */
  --bg-primary: #ffffff;
  --ground: #f9fafc;
  --bg-secondary: #f1f4f7;
  --bg-tertiary: #e7f0f9;
  --border: #c6d2df;
  --border-light: #e1e8ef;

  /* text */
  --text-primary: #1e2a36;
  --text-secondary: #4d5b6a;
  --text-muted: #7b8b9d;

  /* the action color. Blue acts; navy is blue under the cursor. */
  --accent: #326fb6;
  --accent-hover: #013b71;
  --accent-light: #e2edf8;

  /* state, never decoration */
  --green: #0f9d6e;
  --green-light: #e0f4ed;
  --green-dark: #0a6b4b;
  --orange: #a16207;
  --orange-light: #fdf3d9;
  --red: #be123c;
  --red-light: #fdedf1;
  --red-dark: #9c0e31;

  /* Shadows are cast in navy rather than black, so a card sits on the grid
     instead of punching a gray hole in it. */
  --shadow-sm: 0 1px 2px rgb(1 59 113 / 0.06);
  --shadow: 0 1px 3px rgb(1 59 113 / 0.10), 0 1px 2px rgb(1 59 113 / 0.06);
  --shadow-md: 0 4px 10px -2px rgb(1 59 113 / 0.14), 0 2px 5px -3px rgb(1 59 113 / 0.12);

  --radius: 8px;
  --radius-lg: 12px;
  --nav-h: 56px;
  --sidebar-w: 264px;
  --chat-w: 420px;
  --mono: "IBM Plex Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  --cond: "Barlow Condensed", "Barlow", "Segoe UI", sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* The root has to be pinned too. Styling only body leaves html at overflow
   visible, which makes html the scrolling element, and anything that scrolls
   it (a focus call, the browser restoring position on reload) drags the whole
   in-flow layout with it. */
html { height: 100%; overflow: hidden; }

body {
  font-family: "Barlow", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  /* The drafting grid: 56px squares of brand blue at the deck's 5.5 percent,
     held still while the main region scrolls over it. The 5.5 stays even
     though the ground is lighter than the deck's, because on this ground the
     ruling is the only thing separating table from sheet. .main paints no
     background of its own, so this is the table every page is laid on. */
  background-color: var(--ground);
  background-image:
    linear-gradient(rgb(50 111 182 / 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgb(50 111 182 / 0.055) 1px, transparent 1px);
  background-size: 56px 56px;
  background-attachment: fixed;
  color: var(--text-primary);
  line-height: 1.5;
  overflow: hidden;
  height: 100vh;
  -webkit-font-smoothing: antialiased;
}

button { font-family: inherit; }

/* ---------------------------------------------------------------- top nav */

.topnav {
  position: fixed; top: 0; left: 0; right: 0;
  height: var(--nav-h);
  background: var(--bg-primary);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 20px;
  padding: 0 20px;
  z-index: 100;
  box-shadow: var(--shadow-sm);
}
.topnav-left { display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none;
  border-radius: 8px; padding: 4px 6px; margin: -4px -6px; transition: background 0.15s; }
.topnav-left:hover { background: var(--bg-tertiary); }
/* The mark is inked onto the nav rather than knocked out of a chip.
   It used to sit in a 34px rounded square filled with a 135 degree navy to
   blue gradient, white lines on top. Nothing else in the brand is built that
   way: the only gradient in the system is the 2px rule under a group heading,
   and the firm's own mark at the foot of the sidebar is flat navy drawn
   straight on the sheet. So the frame gets drawn on the sheet too, and the
   three depth tiers the projection already carries take a colour and a line
   weight each instead of an opacity. Far edges light and thin, near edges navy
   and full: lighter line means further back is the drafting convention, and
   here it is also what the geometry means. Three of the five corporate colors,
   one hue ramp, no fourth thing invented to fill the box. */
/* The chip used to supply the optical gap. Without it the mark's own margin
   inside the 64 unit box does, and the frame only inks from 8.25 to 55.75, so
   a 26px mark carries 3.4px of air on each side. The lockup was reading 13px
   apart at a 15px cap height. Pull the box back by 4 and the ink sits about
   nine from the S, which is where a two part lockup wants to sit. */
.topnav-logo { display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; margin-right: -4px; }
/* One ink. The tiers were painted sky, blue and navy at three line weights,
   which is four colours across a lockup and reads as decoration rather than as
   a logo. It is also not how the mark is drawn: frame-cubocta.svg paints every
   edge in one colour and separates the tiers by opacity alone, because a tier
   IS the z of an edge. So the mark goes back to that, in navy, at one stroke
   width. The far tier lifts from the file's 0.26 to 0.30 and the middle from
   0.55 to 0.58, because the file is drawn for a 512 px hero and this is 26 px,
   where the back edges thin out before they fade. */
.topnav-logo svg { display: block; stroke: var(--navy); stroke-width: 3.4; }
.topnav-logo .t-far  { opacity: 0.30; }
.topnav-logo .t-mid  { opacity: 0.58; }
.topnav-logo .t-near { opacity: 1; }
/* Two colors, the way the corporate wordmark is always two colors: the
   product name in navy, the Cx that says what it does in blue. The halves
   separate by weight as well as colour, which is what a wordmark does and a
   bold sans with a colour swap on the last two letters does not. Barlow
   Condensed sets about a size small, so 22 here reads as 19 did, and the
   tracking closes to 0 instead of opening: the mark gave up its 34px chip and
   the type takes the width back. */
.topnav-title { font-weight: 600; font-size: 22px; white-space: nowrap;
  color: var(--navy); letter-spacing: 0; line-height: 1; }
.topnav-title i { font-style: normal; }
/* The only --hi on the shell. Demo data is exactly the thing the brand
   reserves orange for: the one fact you are meant to notice first. */
.dev-badge {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  background: var(--hi-soft); color: var(--hi);
  border: 1px solid #f6c3b4;
  padding: 1px 6px; border-radius: 4px;
}

.topnav-search { flex: 1; max-width: 460px; position: relative; }
.topnav-search input {
  width: 100%; height: 34px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-secondary);
  padding: 0 12px 0 32px;
  font-size: 13px; color: var(--text-primary);
  outline: none; transition: border-color 0.15s, background 0.15s;
}
.topnav-search input:focus { border-color: var(--accent); background: var(--bg-primary); }
.topnav-search .search-icon {
  position: absolute; left: 11px; top: 9px;
  color: var(--text-muted); font-size: 13px; pointer-events: none;
}
.search-results {
  position: absolute; top: 40px; left: 0; right: 0;
  background: var(--bg-primary); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: var(--shadow-md);
  max-height: 340px; overflow-y: auto; z-index: 120;
}
/* With nothing in it the box still drew its own border, which is a 2 px line
   under the search field on every page load. The alert menu beside it has had
   this rule all along. */
.search-results:empty { display: none; }
.search-result {
  padding: 8px 12px; font-size: 13px; cursor: pointer;
  display: flex; align-items: center; gap: 8px;
  border-bottom: 1px solid var(--border-light);
}
.search-result:last-child { border-bottom: none; }
.search-result:hover { background: var(--bg-tertiary); }
.search-result .sr-sub { margin-left: auto; font-size: 11px; color: var(--text-muted); }

.topnav-right { display: flex; align-items: center; gap: 12px; margin-left: auto; }
/* The as-of pill that used to sit here is gone. It carried one date that
   never changed and a dot with one state, next to the controls a person
   actually reaches for, and the Fleet overview subtitle says the same date in
   prose. The screens that need the window still state it themselves.

   The alert bell went the same way on 2026-09-02, and with it .icon-btn,
   .badge-count, .topnav-alerts and the whole .alert-menu block: nothing else
   in the app used any of them. A solid red counter on a fleet-wide number that
   never reaches zero is the social-media pattern, and it trains people to
   ignore the one control that is supposed to mean something. The count still
   sits on the sidebar Alerts item as a muted pill and on the overview tile. */

.chat-toggle {
  background: var(--bg-tertiary); border: 1px solid var(--border);
  border-radius: 20px; padding: 6px 16px;
  font-size: 13px; font-weight: 500; cursor: pointer;
  white-space: nowrap; transition: all 0.15s;
}
.chat-toggle:hover, .chat-toggle.active {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--accent-light); color: var(--accent-hover);
  font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; user-select: none;
}

/* ---------------------------------------------------------------- sidebar */

.sidebar {
  position: fixed; top: var(--nav-h); left: 0; bottom: 0;
  width: var(--sidebar-w);
  background: var(--bg-primary);
  border-right: 1px solid var(--border);
  overflow-y: auto; padding: 14px 0;
  z-index: 50;
  /* A column, so the vendor lockup can take the floor with margin-top: auto
     and still scroll away with the content when the nav is long. */
  display: flex; flex-direction: column;
}
.sidebar > * { flex-shrink: 0; }
.sidebar-section { padding: 0 14px; margin-bottom: 14px; }
/* Sidebar greys, darkened. Headings go 2.8:1 -> 7.5:1 against white, items
   4.8:1 -> 10.4:1. Hierarchy still reads, both now pass AA comfortably. */
.sidebar-heading {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.5px; color: var(--text-secondary); margin-bottom: 7px;
}
.sidebar-divider { height: 1px; background: var(--border-light); margin: 0 14px 12px 14px; }

.nav-item {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 11px; margin: 2px 0; border-radius: 6px;
  font-size: 13px; color: var(--text-secondary);
  cursor: pointer; transition: all 0.15s; user-select: none;
}
.nav-item:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.nav-item.active { background: var(--accent-light); color: var(--accent-hover); font-weight: 600; }
.nav-item .nav-glyph {
  width: 18px; text-align: center; font-size: 13px; opacity: 1;
  color: var(--text-secondary); flex-shrink: 0;
}
.nav-item.active .nav-glyph { color: inherit; }
.nav-count {
  margin-left: auto; font-size: 11px; font-weight: 700;
  padding: 1px 7px; border-radius: 10px;
  background: var(--bg-secondary); color: var(--text-secondary);
}
.nav-item.active .nav-count { background: var(--accent); color: #fff; }
.nav-count.alarm { background: var(--red-light); color: var(--red-dark); }

.filter-group { margin-bottom: 12px; }
.filter-label {
  font-size: 11px; font-weight: 600; color: var(--text-secondary);
  margin-bottom: 5px; display: flex; align-items: center;
}
.filter-label .clear-link {
  margin-left: auto; font-weight: 500; color: var(--accent);
  cursor: pointer; font-size: 10px;
}
.check-row {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 0; font-size: 12.5px; cursor: pointer; user-select: none;
  color: var(--text-primary);
}
.filter-label { color: var(--text-secondary); }
.check-row .row-count { color: var(--text-secondary); }
.check-row input { accent-color: var(--accent); width: 14px; height: 14px; cursor: pointer; }
.check-row .row-count { margin-left: auto; font-size: 11px; color: var(--text-muted); }
.check-row:hover { color: var(--accent-hover); }

.chip-row { display: flex; flex-wrap: wrap; gap: 5px; }
.chip {
  font-size: 11px; font-weight: 500;
  padding: 3px 9px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--bg-primary);
  color: var(--text-secondary); cursor: pointer; user-select: none;
  transition: all 0.15s;
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ------------------------------------------------------------ main region */

.main {
  position: fixed;
  top: var(--nav-h); left: var(--sidebar-w); right: 0; bottom: 0;
  overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain;
}
.main.chat-open { right: var(--chat-w); }
.page { padding: 20px 24px 60px 24px; max-width: 1500px; }

.page-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 16px; }
.page-title { font-size: 21px; font-weight: 700; letter-spacing: -0.2px; }
.page-sub { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }
.page-head-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 13px; border-radius: 6px;
  font-size: 12.5px; font-weight: 500;
  border: 1px solid var(--border); background: var(--bg-primary);
  color: var(--text-secondary); cursor: pointer; transition: all 0.15s;
}
.btn:hover { background: var(--bg-secondary); color: var(--text-primary); border-color: var(--accent); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.primary:hover { background: var(--accent-hover); color: #fff; }
.btn.ghost { border-color: transparent; background: transparent; }

/* ------------------------------------------------------------- stat tiles */

.stat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 12px; margin-bottom: 18px;
}
.stat-tile {
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius-lg); padding: 13px 15px;
  box-shadow: var(--shadow-sm); transition: all 0.15s;
}
.stat-tile.clickable { cursor: pointer; }
.stat-tile.clickable:hover { border-color: var(--accent); box-shadow: var(--shadow-md); }
.stat-label {
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.4px; color: var(--text-muted);
}
.stat-value {
  font-size: 25px; font-weight: 700; line-height: 1.15; margin-top: 5px;
  letter-spacing: -0.5px; font-variant-numeric: tabular-nums;
}
.stat-value .unit {
  font-size: 14px; font-weight: 600; color: var(--text-muted);
  /* A tile that carries two numbers ran the first unit into the second
   * number with nothing between them. The right margin does nothing on a
   * tile whose unit is last. */
  margin-left: 3px; margin-right: 8px;
}
.stat-foot { display: flex; align-items: center; gap: 6px; margin-top: 6px; font-size: 11.5px; }
.delta { font-weight: 600; font-variant-numeric: tabular-nums; }
.delta.up { color: var(--red-dark); }
.delta.down { color: var(--green-dark); }
.delta.flat { color: var(--text-muted); }
.delta.good-up { color: var(--green-dark); }
.stat-foot .stat-note { color: var(--text-muted); }
.stat-spark { margin-top: 8px; height: 30px; }

/* ---------------------------------------------------------------- panels */

.panel {
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  margin-bottom: 16px; overflow: hidden;
}
.panel-head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 16px; border-bottom: 1px solid var(--border-light);
}
.panel-title { font-size: 14px; font-weight: 600; }
.panel-sub { font-size: 12px; color: var(--text-muted); }
.panel-head-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.panel-body { padding: 14px 16px; }
.panel-body.tight { padding: 0; overflow-x: auto; }

/* align-items:start so a short panel sizes to its content instead of
   stretching to match a tall neighbour and leaving dead space under a chart. */
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  gap: 16px; align-items: start; }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px; align-items: start; }

/* ----------------------------------------------------------------- tables */

table.dt { width: 100%; border-collapse: collapse; font-size: 12.5px; }
table.dt th {
  text-align: left; font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted);
  padding: 9px 12px; border-bottom: 1px solid var(--border);
  background: var(--bg-secondary); white-space: nowrap;
}
table.dt th.sortable { cursor: pointer; user-select: none; }
table.dt th.sortable:hover { color: var(--accent); }
table.dt th .sort-arrow { font-size: 9px; margin-left: 3px; }
table.dt td {
  padding: 8px 12px; border-bottom: 1px solid var(--border-light);
  vertical-align: middle;
}
table.dt tbody tr:hover { background: var(--bg-tertiary); }
table.dt tbody tr.clickable { cursor: pointer; }
table.dt td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* The markup convention was already here and nothing was reading it. Every
   numeric column in the app ships <th class="num"> and has since the tables
   were written, but no rule ever matched it, so the label sat hard left over a
   right-aligned column of numbers in every table on the site. A number and its
   heading share an edge or the eye has to count columns to find out which
   figure it is looking at. */
table.dt th.num { text-align: right; }

/* Six of the fourteen columns on the stations table carry a sparkline under
   the number and the other eight do not, so a middle-aligned row staircases:
   Control pts puts its 88 at the top of a two line cell while Edits 7d floats
   its 0 to the middle of the same row, and the station name, the client and
   the version float with it. Every value in a row reads on one baseline and
   the sparklines hang below it. Scoped to this table because it is the only
   one that mixes cell heights inside a row. */
table.dt.stations td { vertical-align: top; }

/* A value that is one token reads as two when it wraps. Squeeze the stations
   table and the host lands over its case-sensitivity pill, and an SMA date
   breaks at a hyphen into 2027-01- over 19, which is not a date. The prose
   columns still wrap, because a client and site is a phrase; this is for the
   cells that hold exactly one thing. The table already scrolls sideways under
   .table-wrap, so widening one is cheaper than breaking a value in half. */
table.dt td.nw { white-space: nowrap; }
table.dt td.mono { font-family: var(--mono); font-size: 11.5px; color: var(--text-secondary); }
.table-wrap {
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--bg-primary) 30%, rgba(255, 255, 255, 0)) left center,
    linear-gradient(to left, var(--bg-primary) 30%, rgba(255, 255, 255, 0)) right center,
    radial-gradient(farthest-side at 0 50%, rgba(15, 23, 42, 0.13), rgba(15, 23, 42, 0)) left center,
    radial-gradient(farthest-side at 100% 50%, rgba(15, 23, 42, 0.13), rgba(15, 23, 42, 0)) right center;
  background-repeat: no-repeat;
  background-size: 36px 100%, 36px 100%, 13px 100%, 13px 100%;
  background-attachment: local, local, scroll, scroll;
}

/* Label / value / note table. The value column is pinned so the number sits
   next to its label instead of drifting into the middle of the panel. */
table.dt.kv td:first-child { width: 320px; }
table.dt.kv td:nth-child(2) { width: 80px; }

.link { color: var(--accent); cursor: pointer; font-weight: 500; }
.link:hover { text-decoration: underline; }

/* ------------------------------------------------------------ badges/pills */

.pill {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.4px; padding: 2px 8px; border-radius: 4px;
  white-space: nowrap;
}
.pill.critical { background: var(--red-light); color: var(--red-dark); }
.pill.high { background: var(--red-light); color: var(--red-dark); }
.pill.medium { background: var(--orange-light); color: var(--orange); }
.pill.low, .pill.info { background: var(--bg-secondary); color: var(--text-secondary); }
.pill.ok { background: var(--green-light); color: var(--green-dark); }
.pill.error { background: var(--red-light); color: var(--red-dark); }
.pill.warn { background: var(--orange-light); color: var(--orange); }

.tag {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 22px; padding: 0 6px;
  border-radius: 5px; font-size: 10px; font-weight: 700;
  letter-spacing: 0.4px; flex-shrink: 0;
}
/* Thirteen kinds against five corporate colors. The three letter code is what
   names the kind; the color only has to group them. So they run down the
   brand's own blue ramp, the three state colors do state, and the rest sit
   neutral. Thirteen hues was a rainbow that told nobody anything, and none of
   them earns --hi: a code that shows up forty times in a table is not a
   highlight. */
.tag.PTS { background: #dee9f5; color: #245a97; }
.tag.DEV { background: #e7f0f9; color: #2d6a99; }
.tag.COM { background: #e7f0f9; color: #2d6a99; }
.tag.PX  { background: #e3eaf3; color: var(--navy); }
.tag.LIC { background: #e3eaf3; color: var(--navy); }
.tag.SCH { background: var(--orange-light); color: var(--orange); }
.tag.ALM { background: var(--red-light); color: var(--red-dark); }
.tag.VER { background: var(--green-light); color: var(--green-dark); }
.tag.QC  { background: var(--green-light); color: var(--green-dark); }
.tag.USR { background: #e7ebf1; color: var(--text-primary); }
.tag.OVR { background: #e7ebf1; color: var(--text-primary); }
/* Histories. The thirteenth kind arrived without a rule and rendered as an
   invisible badge against twelve styled siblings. Neutral, not a new hue. */
.tag.HB  { background: #eef2f6; color: var(--text-secondary); }
.tag.HIS { background: #eef2f6; color: var(--text-secondary); }

.meta-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; color: var(--text-secondary);
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-radius: 5px; padding: 3px 8px; white-space: nowrap;
}
.meta-chip b { color: var(--text-primary); font-weight: 600; }

.status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.status-dot.ok { background: var(--green); }
.status-dot.warn { background: var(--orange); }
.status-dot.err { background: var(--red); }
.status-dot.off { background: var(--text-muted); }

/* ------------------------------------------------------------- change feed */

/* Feed search bar and priority chips. */
.feed-select:focus { border-color: var(--accent); }

.feed-filters {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-bottom: 14px;
}
/* The change card, its eleven parts and the banner tier head that sat above it
 * are gone. A row and a section stripe do the same work in a fifth of the
 * paint: see the quiet row block at the end of this file. */

/* Group header row inside a data table. Full width, so the columns below it
   still line up with every other row in the same table. */
tr.group-row td {
  background: var(--red-light);
  padding: 9px 12px;
  border-bottom: 1px solid #f0c2ce;
}
tr.group-row td > * { vertical-align: middle; }
tr.group-row b { margin: 0 8px 0 8px; font-size: 12.5px; }
tr.group-row span:last-child { font-size: 11.5px; color: var(--red-dark); }
table.dt tbody tr.group-row:hover td { background: var(--red-light); }
tr.in-group td:first-child { padding-left: 26px; }

.dim { color: var(--text-muted); }

.trunk-head {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 11px 16px 9px 16px; font-size: 12.5px;
  background: var(--red-light);
  border-top: 1px solid var(--border-light);
}
.trunk-head:first-child { border-top: none; }

/* ------------------------------------------------------------- heat matrix */

.heat { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12px; }
.heat th { font-size: 10px; color: var(--text-muted); font-weight: 600; padding: 0 0 6px 0; }
.heat td.hname {
  padding: 0 10px 0 14px; white-space: nowrap; font-size: 12.5px;
  max-width: 210px; overflow: hidden; text-overflow: ellipsis;
}
.heat td.hname .hsite { color: var(--text-muted); font-size: 11px; }
.heat td.hcells { padding: 2px 14px 2px 0; width: 100%; }
.heat tr.clickable:hover td { background: var(--bg-tertiary); }
.heat tr.clickable { cursor: pointer; }
.heat-strip { display: flex; gap: 2px; }
.heat-cell { flex: 1; height: 20px; border-radius: 2px; min-width: 4px; }
.heat-cell.c-ok { background: #b7e4d1; }
.heat-cell.c-quiet { background: #e1e8ef; }
.heat-cell.c-work { background: #aecdea; }
.heat-cell.c-warn { background: #fae2b3; }
.heat-cell.c-err { background: #f0c2ce; }
.heat-cell.c-off { background: #eef2f6; border: 1px dashed #c6d2df; }
.heat-legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 11.5px; color: var(--text-secondary); }
.heat-legend span.k { display: inline-flex; align-items: center; gap: 5px; }
.heat-legend i { width: 11px; height: 11px; border-radius: 2px; display: inline-block; }

/* ------------------------------------------------------ station detail view */

.st-header {
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: 16px 18px; margin-bottom: 16px;
}
.st-header-top { display: flex; align-items: flex-start; gap: 12px; }
.st-name { font-size: 20px; font-weight: 700; letter-spacing: -0.2px; }
.st-path { font-size: 12.5px; color: var(--text-secondary); margin-top: 2px; }
.st-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }

.tabs {
  display: flex; flex-wrap: wrap; gap: 2px;
  border-bottom: 1px solid var(--border); margin-bottom: 16px;
}
.tab {
  padding: 8px 14px; font-size: 13px; font-weight: 500;
  color: var(--text-secondary); cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: all 0.15s; user-select: none; white-space: nowrap;
}
.tab:hover { color: var(--text-primary); }
.tab.active { color: var(--accent-hover); border-bottom-color: var(--accent); font-weight: 600; }
.tab .tab-count { font-size: 11px; color: var(--text-muted); margin-left: 5px; }

.chart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 14px; }
.chart-box {
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius-lg); padding: 12px 14px; box-shadow: var(--shadow-sm);
}
.chart-box h4 {
  font-size: 12.5px; font-weight: 600; margin-bottom: 2px;
  display: flex; align-items: center; gap: 8px;
}
.chart-box h4 .cur { margin-left: auto; font-variant-numeric: tabular-nums; }
.chart-box .chart-sub { font-size: 11px; color: var(--text-muted); margin-bottom: 8px; }

.timeline { position: relative; padding-left: 22px; }
.timeline::before {
  content: ""; position: absolute; left: 6px; top: 4px; bottom: 4px;
  width: 2px; background: var(--border-light);
}
.tl-item { position: relative; padding: 0 0 16px 0; }
.tl-item::before {
  content: ""; position: absolute; left: -20px; top: 5px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--bg-primary); border: 2px solid var(--border);
}
.tl-item.sev-high::before, .tl-item.sev-critical::before { border-color: var(--red); background: var(--red-light); }
.tl-item.sev-medium::before { border-color: var(--orange); background: var(--orange-light); }
.tl-date { font-size: 11px; color: var(--text-muted); font-weight: 600; }
.tl-title { font-size: 13px; font-weight: 600; margin-top: 1px; }
.tl-detail { font-size: 12px; color: var(--text-secondary); margin-top: 2px; line-height: 1.5; }

.bar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 7px; font-size: 12.5px; }
.bar-row.clickable { cursor: pointer; border-radius: 4px; padding: 2px 4px; margin-left: -4px;
  margin-right: -4px; }
.bar-row.clickable:hover { background: var(--bg-secondary); }
.bar-row.clickable:hover .bl { color: var(--accent); }
.bar-row .bl { width: 190px; flex-shrink: 0; color: var(--text-secondary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-row .bt { flex: 1; height: 16px; background: var(--bg-secondary); border-radius: 3px; overflow: hidden; }
.bar-row .bt > .bf { display: block; height: 100%; min-width: 2px;
  border-radius: 3px; background: var(--accent); }
.bar-row .bf.red { background: var(--red); }
.bar-row .bf.orange { background: var(--orange); }
.bar-row .bv { width: 46px; text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }

.progress { height: 7px; background: var(--bg-secondary); border-radius: 4px; overflow: hidden; width: 100%; }
.progress > span { display: block; height: 100%; background: var(--accent); }
.progress > span.warn { background: var(--orange); }
.progress > span.err { background: var(--red); }

.empty {
  padding: 44px 20px; text-align: center; color: var(--text-muted); font-size: 13px;
}

/* --------------------------------------------------------------- chat pane */

.chat-panel {
  position: fixed; right: 0; top: var(--nav-h); bottom: 0;
  width: var(--chat-w);
  background: var(--bg-primary); border-left: 1px solid var(--border);
  display: flex; flex-direction: column; z-index: 90;
  box-shadow: -2px 0 8px rgb(0 0 0 / 0.05);
}
.chat-head {
  padding: 14px 16px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 14px;
}
.chat-head .close { margin-left: auto; cursor: pointer; color: var(--text-muted); font-size: 16px; }
.chat-msgs { flex: 1; overflow-y: auto; padding: 16px; }
.chat-msg { margin-bottom: 14px; }
.chat-bubble {
  display: inline-block; padding: 10px 13px; border-radius: 12px;
  max-width: 92%; font-size: 13px; line-height: 1.55;
}
.chat-msg.user { text-align: right; }
.chat-msg.user .chat-bubble { background: var(--accent); color: #fff; border-bottom-right-radius: 4px; }
.chat-msg.bot .chat-bubble { background: var(--bg-secondary); color: var(--text-primary); border-bottom-left-radius: 4px; }
.chat-bubble table { border-collapse: collapse; margin: 8px 0; font-size: 12px; width: 100%; }
.chat-bubble th, .chat-bubble td { border: 1px solid var(--border); padding: 3px 7px; text-align: left; }
.chat-bubble th { background: var(--bg-tertiary); font-weight: 600; }
.chat-cite {
  margin-top: 7px; font-size: 11px; color: var(--text-muted);
  border-top: 1px solid var(--border-light); padding-top: 6px;
}
.chat-suggest { display: flex; flex-direction: column; gap: 6px; padding: 0 16px 12px 16px; }
.chat-suggest button {
  text-align: left; font-size: 12px; padding: 8px 11px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-primary); color: var(--text-secondary); cursor: pointer;
  transition: all 0.15s;
}
.chat-suggest button:hover { border-color: var(--accent); color: var(--accent); background: var(--bg-tertiary); }
.chat-input { padding: 12px 16px; border-top: 1px solid var(--border); display: flex; gap: 8px; }
.chat-input input {
  flex: 1; border: 1px solid var(--border); border-radius: 8px;
  padding: 8px 11px; font-size: 13px; outline: none; font-family: inherit;
}
.chat-input input:focus { border-color: var(--accent); }

/* The head says which conversation is open and carries the two controls that
 * start a new one or go read the old ones. */
.chat-head-t { min-width: 0; }
.chat-head-sub {
  font-size: 11px; font-weight: 400; color: var(--text-muted); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-head-acts {
  margin-left: auto; display: flex; align-items: center; gap: 10px; flex-shrink: 0;
}
.chat-head-acts .close { margin-left: 0; }
.chat-head .act {
  font-size: 11.5px; font-weight: 500; color: var(--text-secondary);
  cursor: pointer; border-bottom: 1px solid transparent;
}
.chat-head .act:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* The same suggestion buttons laid out across a page instead of down a rail. */
.chat-suggest.wide { flex-direction: row; flex-wrap: wrap; padding: 0; }

/* -------------------------------------------------------- conversation log */

.thread { border-top: 1px solid var(--border-light); }
.thread:first-child { border-top: none; }
.thread-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; cursor: pointer; font-size: 13px;
}
.thread-row:hover { background: var(--bg-tertiary); }
.thread.open .thread-row { background: var(--bg-secondary); font-weight: 600; }
.thread-caret { width: 12px; color: var(--text-muted); font-size: 10px; flex-shrink: 0; }
.thread-title {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.thread-meta {
  font-size: 11.5px; color: var(--text-muted); font-weight: 400;
  white-space: nowrap; flex-shrink: 0;
}
.thread-acts { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.thread-acts .btn { padding: 3px 10px; font-size: 11.5px; }
.thread-acts .btn.ghost {
  color: var(--text-muted); padding: 2px 8px; font-size: 15px; line-height: 1.2;
}
.thread-acts .btn.ghost:hover { color: var(--red-dark); background: var(--red-light); }

/* Same bubbles as the rail, but a page is wider than 420 px and a bubble that
 * runs the full width of one is unreadable. */
.chat-log {
  padding: 14px 16px 16px 32px; background: var(--bg-secondary);
  border-top: 1px solid var(--border-light);
}
.chat-log .chat-bubble { max-width: 720px; }
.chat-log .chat-msg.bot .chat-bubble {
  background: var(--bg-primary); border: 1px solid var(--border-light);
}
.log-when { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; text-align: right; }

/* --------------------------------------------------------------- svg chart */

.svg-chart { width: 100%; display: block; overflow: visible; }
.svg-chart .grid-line { stroke: var(--border-light); stroke-width: 1; }
.svg-chart .axis-label { font-size: 9.5px; fill: var(--text-muted); }
.svg-chart .series-line { fill: none; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; }
.svg-chart .series-area { opacity: 0.13; }
.svg-chart .marker { stroke-width: 1; stroke-dasharray: 3 3; }
.svg-chart .hover-target { fill: transparent; cursor: crosshair; }
.chart-tip {
  position: fixed; pointer-events: none; z-index: 500;
  background: var(--navy); color: #fff; font-size: 11.5px;
  padding: 6px 9px; border-radius: 6px; line-height: 1.5;
  box-shadow: var(--shadow-md); white-space: nowrap; opacity: 0;
  transition: opacity 0.1s;
}
.chart-legend { display: flex; flex-wrap: wrap; gap: 12px; font-size: 11.5px;
  color: var(--text-secondary); margin-top: 8px; }
.chart-legend .lk { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.chart-legend .lk i { width: 10px; height: 3px; border-radius: 2px; display: inline-block; }
.chart-legend .lk.off { opacity: 0.35; }

@media (max-width: 1100px) {
  .sidebar { display: none; }
  .main { left: 0; }
  .main.chat-open { right: 0; }
  .chat-panel { display: none; }
}

/* ------------------------------------------------ feed search and triage */

.feed-search {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 10px;
  margin-bottom: 10px;
  box-shadow: var(--shadow-sm);
}
.feed-search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.feed-search .fs-icon { color: var(--text-muted); font-size: 14px; flex-shrink: 0; }
.feed-search input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: transparent;
  font-family: inherit; font-size: 13px; color: var(--text-primary);
  padding: 4px 0;
}
.feed-search input::placeholder { color: var(--text-muted); }
.fs-clear {
  font-size: 11px; color: var(--accent); cursor: pointer; font-weight: 500;
  padding: 2px 6px; border-radius: 4px;
}
.fs-clear:hover { background: var(--accent-light); }
.feed-select {
  border: 1px solid var(--border); border-radius: 6px; background: var(--bg-secondary);
  font-family: inherit; font-size: 12px; color: var(--text-secondary);
  padding: 4px 8px; max-width: 190px;
}

.chip-sep {
  width: 1px; height: 18px; display: inline-block;
  background: var(--border-light); margin: 0 3px;
}
.chip.prio { font-weight: 600; }
.chip.prio.t1 { border-color: #ecb4c2; color: var(--red-dark); }
.chip.prio.t1.on { background: var(--red-dark); border-color: var(--red-dark); color: #fff; }
.chip.prio.t2 { border-color: #e7cd92; color: var(--orange); }
.chip.prio.t2.on { background: var(--orange); border-color: var(--orange); color: #fff; }
.chip.prio.t3 { border-color: var(--border); color: var(--text-secondary); }
.chip.prio.t3.on { background: var(--text-secondary); border-color: var(--text-secondary); color: #fff; }

/* ------------------------------------------------------- needs a decision */

.panel.attention { border-color: #f0c2ce; }
.panel.attention .panel-title { color: var(--red-dark); }
table.att td { vertical-align: top; padding: 9px 10px; }
table.att tr + tr td { border-top: 1px solid var(--border-light); }
.att-sev { width: 82px; }
/* The tier word, in the tier color, the same three the feed and the punch list
 * use. Five severity pills for one idea was two vocabularies on one screen. */
.att-tier {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.4px;
  text-transform: uppercase; white-space: nowrap;
}
.att-tier.t1 { color: var(--red-dark); }
.att-tier.t2 { color: var(--orange); }
.att-tier.t3 { color: var(--text-muted); }
.att-disp { width: 58px; }
.att-title { font-size: 13px; font-weight: 600; line-height: 1.35; }
.att-why { font-size: 11.5px; color: var(--text-secondary); margin-top: 2px; line-height: 1.45; }
.att-st { width: 190px; font-size: 12px; font-weight: 500; }
.att-site { font-size: 11px; color: var(--text-muted); font-weight: 400; margin-top: 1px; }
.att-age { width: 92px; font-size: 11.5px; color: var(--text-muted); white-space: nowrap; }
.att-more { font-size: 11.5px; color: var(--text-muted); padding: 9px 10px 2px 10px; }

/* ------------------------------------------------------------ saved trends */

.trend-save { margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--border-light); }
.ts-row { display: flex; gap: 8px; align-items: center; margin-bottom: 9px; }
.ts-row input {
  flex: 1; max-width: 320px;
  border: 1px solid var(--border); border-radius: 6px;
  font-family: inherit; font-size: 13px; padding: 7px 10px;
  color: var(--text-primary); background: var(--bg-primary);
}
.ts-row input:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.ts-empty { font-size: 11.5px; color: var(--text-muted); }
.chip.saved { display: inline-flex; align-items: center; gap: 7px; padding-right: 4px; }
.chip.saved .ts-meta { font-size: 10.5px; color: var(--text-muted); font-weight: 400; }
.chip.saved.on .ts-meta, .chip.saved:hover .ts-meta { color: inherit; opacity: .75; }
.ts-x {
  font-size: 13px; line-height: 1; color: var(--text-muted);
  padding: 2px 5px; border-radius: 4px;
}
.ts-x:hover { background: var(--red-light); color: var(--red-dark); }

/* ------------------------------------------------------ heartbeat continuity */

.hb-foot {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 7px; font-size: 11px; color: var(--text-muted);
}
.hb-foot b { color: var(--text-secondary); font-weight: 600; }
.hb-foot span:nth-child(2) { color: var(--text-secondary); }

/* ==========================================================================
   Sidebar customization: reorder, hide, and the plus that adds a dashboard
   ========================================================================== */

.sidebar-heading.nav-heading {
  display: flex; align-items: center; gap: 6px; min-height: 22px;
}
/* No size of its own. A group head and the Recent head are the same rank to
   somebody reading the column, and this override was what made the groups the
   smallest type in the sidebar. The caret and the divider carry the level. */
.nav-tools { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.nav-tool {
  font-size: 10px; font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--text-muted);
  padding: 1px 6px; border-radius: 4px; cursor: pointer;
  border: 1px solid transparent;
}
.nav-tool:hover { background: var(--bg-tertiary); color: var(--accent); border-color: var(--border); }
.nav-tool.on { background: var(--accent-light); color: var(--accent-hover); }
.nav-tool[data-newdash] { font-size: 14px; line-height: 12px; padding: 1px 7px 3px 7px; }

.nav-item .nav-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-item.editing { cursor: grab; }
.nav-item.editing:active { cursor: grabbing; }
.nav-item.off { opacity: 0.45; }
.nav-item.off .nav-label { text-decoration: line-through; }
.nav-grip { width: 18px; text-align: center; font-size: 11px; color: var(--text-muted); flex-shrink: 0; }
.nav-eye {
  margin-left: auto; font-size: 11px; color: var(--text-muted);
  padding: 0 5px; border-radius: 4px; flex-shrink: 0;
}
.nav-eye:hover { background: var(--bg-tertiary); color: var(--accent); }
.nav-foot {
  display: flex; justify-content: space-between; gap: 8px;
  font-size: 10.5px; color: var(--text-muted); padding: 6px 11px 0 11px;
}
.nav-foot span:first-child { color: var(--accent); cursor: pointer; }
.nav-foot span:first-child:hover { text-decoration: underline; }

/* Drop indicator. A line, not a gap, so nothing reflows mid drag. */
.dragging { opacity: 0.4; }
.drop-before { box-shadow: inset 0 2px 0 0 var(--accent); }
.drop-after { box-shadow: inset 0 -2px 0 0 var(--accent); }
.dash-grid .drop-before { box-shadow: inset 2px 0 0 0 var(--accent); }
.dash-grid .drop-after { box-shadow: inset -2px 0 0 0 var(--accent); }

/* ==========================================================================
   Modal
   ========================================================================== */

.modal-host {
  position: fixed; inset: 0; z-index: 300;
  background: rgb(11 18 32 / 0.45);
  display: none; align-items: flex-start; justify-content: center;
  padding: 60px 20px 20px 20px; overflow-y: auto;
}
.modal-host.open { display: flex; }
.modal {
  background: var(--bg-primary); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md); width: 100%; max-width: 520px;
  max-height: calc(100vh - 90px); display: flex; flex-direction: column;
}
.modal.wide { max-width: 780px; }
.modal-head {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 15px 18px; border-bottom: 1px solid var(--border-light);
}
.modal-title { font-size: 15px; font-weight: 700; }
.modal-sub { font-size: 12px; color: var(--text-secondary); margin-top: 2px; line-height: 1.5; }
.modal-x {
  margin-left: auto; font-size: 20px; line-height: 1; color: var(--text-muted);
  cursor: pointer; padding: 0 4px; border-radius: 4px;
}
.modal-x:hover { background: var(--bg-secondary); color: var(--text-primary); }
.modal-body { padding: 16px 18px; overflow-y: auto; }
.modal-foot {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 18px; border-top: 1px solid var(--border-light);
  background: var(--bg-secondary);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.modal-foot .btn:first-of-type { margin-left: auto; }
.modal-foot-note { font-size: 11px; color: var(--text-muted); line-height: 1.45; flex: 1; }
.confirm-text { font-size: 13px; color: var(--text-secondary); line-height: 1.6; }

/* ==========================================================================
   Form rows, shared by the widget editor, the grant dialog and settings
   ========================================================================== */

.f-row { display: flex; gap: 14px; padding: 11px 0; border-top: 1px solid var(--border-light); }
.f-row:first-child { border-top: none; padding-top: 0; }
.f-label {
  width: 150px; flex-shrink: 0; font-size: 12px; font-weight: 600;
  color: var(--text-secondary); padding-top: 5px;
}
.f-body { flex: 1; min-width: 0; }
.f-input {
  width: 100%; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg-primary); color: var(--text-primary);
  font-family: inherit; font-size: 13px; padding: 7px 10px; outline: none;
}
textarea.f-input { resize: vertical; line-height: 1.55; }
.f-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.f-hint { font-size: 11.5px; color: var(--text-muted); margin-top: 6px; line-height: 1.5; }
.f-warn {
  margin-top: 12px; padding: 9px 12px; border-radius: 6px;
  background: var(--orange-light); color: var(--orange);
  font-size: 12.5px; line-height: 1.5;
}
.f-ok {
  margin-top: 12px; padding: 9px 12px; border-radius: 6px;
  background: var(--bg-secondary); color: var(--text-secondary);
  font-size: 12.5px; line-height: 1.5; border-left: 2px solid var(--accent);
}
.chip.off { opacity: 0.4; cursor: not-allowed; }
.chip.off:hover { border-color: var(--border); color: var(--text-secondary); }

.pick-groups { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.pick-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.4px; color: var(--text-muted); margin-bottom: 5px;
}
.pick-all {
  margin-left: auto; font-size: 10px; color: var(--accent); cursor: pointer;
  text-transform: none; letter-spacing: 0; font-weight: 500;
}
.pick-all:hover { text-decoration: underline; }

.switch {
  display: inline-block; width: 34px; height: 20px; border-radius: 10px;
  background: var(--border); cursor: pointer; vertical-align: middle;
  transition: background 0.15s; position: relative;
}
.switch i {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; box-shadow: var(--shadow-sm);
  transition: left 0.15s;
}
.switch.on { background: var(--accent); }
.switch.on i { left: 16px; }
.switch-state { font-size: 12px; color: var(--text-secondary); margin-left: 8px; }


/* How many rows the filter left, and which saved view is scoping them. A
   caption over the table, not a boxed note beside it. */
.table-count {
  font-size: 11.5px; color: var(--text-secondary); margin: 0 0 7px 2px;
  font-variant-numeric: tabular-nums;
}

.btn.danger { color: var(--red-dark); border-color: #f0c2ce; }
.btn.danger:hover { background: var(--red-light); border-color: var(--red); color: var(--red-dark); }
.btn.off { opacity: 0.45; cursor: not-allowed; }
.btn.off:hover { background: var(--accent); }

/* ==========================================================================
   Dashboards
   ========================================================================== */

.dash-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 14px; align-items: start; }
.dash-name {
  font-size: 21px; font-weight: 700; letter-spacing: -0.2px;
  border: 1px solid var(--border); border-radius: 6px;
  padding: 3px 9px; width: 100%; max-width: 460px;
  font-family: inherit; color: var(--text-primary); background: var(--bg-primary);
  outline: none;
}
.dash-name:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.dash-hint { font-size: 11.5px; color: var(--text-muted); margin-top: 14px; }

.w {
  position: relative; min-width: 0;
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.dash-grid.editing .w { border-color: var(--border); }
.w-head { display: flex; align-items: flex-start; gap: 8px; padding: 12px 14px 0 14px; }
.w-grip { font-size: 11px; color: var(--text-muted); cursor: grab; padding-top: 2px; }
.w-titles { min-width: 0; flex: 1; }
.w-title {
  font-size: 12.5px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.w-sub { font-size: 11px; color: var(--text-muted); margin-top: 1px; }
.w-tools { display: flex; gap: 3px; flex-shrink: 0; }
.w-tool {
  font-size: 10.5px; color: var(--text-muted); cursor: pointer;
  padding: 2px 6px; border-radius: 4px; border: 1px solid transparent;
}
.w-tool:hover { background: var(--bg-tertiary); color: var(--accent); border-color: var(--border); }
.w-tool.danger:hover { background: var(--red-light); color: var(--red-dark); border-color: #f0c2ce; }
.w-body { padding: 10px 14px 14px 14px; }
.w-body .empty { padding: 22px 10px; }
.w-body table.dt { font-size: 12px; }
.w-resize {
  position: absolute; right: 0; bottom: 0; width: 16px; height: 16px;
  cursor: nwse-resize;
  background: linear-gradient(135deg, transparent 50%, var(--border) 50%, var(--border) 62%,
    transparent 62%, transparent 76%, var(--border) 76%, var(--border) 88%, transparent 88%);
}
.w-resize:hover { background: linear-gradient(135deg, transparent 45%, var(--accent) 45%); }
body.resizing { user-select: none; cursor: nwse-resize; }

.w.is-note { background: var(--bg-tertiary); border-color: var(--border-light); box-shadow: none; }
.w.is-note .w-title { font-size: 13.5px; }
.w-note { font-size: 12.5px; color: var(--text-secondary); line-height: 1.6; }
.w-note-empty { font-size: 12px; color: var(--text-muted); }

.w-stat .stat-value {
  font-size: 25px; font-weight: 700; letter-spacing: -0.5px;
  line-height: 1.15; font-variant-numeric: tabular-nums;
}
.w-rank .bar-row .bl { width: 150px; }
.w-rank .bar-row.clickable { cursor: pointer; }
.w-rank .bar-row.clickable:hover .bl { color: var(--accent); }

.w-alerts { display: flex; flex-direction: column; }
.wa-row {
  display: flex; gap: 8px; align-items: flex-start; padding: 7px 0; cursor: pointer;
  border-bottom: 1px solid var(--border-light);
}
.wa-row:last-child { border-bottom: none; }
.wa-row:hover .wa-what { color: var(--accent-hover); }
.wa-body { min-width: 0; }
.wa-what { font-size: 12px; font-weight: 600; line-height: 1.35; }
.wa-sub { font-size: 11px; color: var(--text-muted); margin-top: 1px; }
.wa-more { font-size: 11px; color: var(--text-muted); padding-top: 8px; }

.stat-tile { position: relative; }
.tile-add {
  position: absolute; top: 6px; right: 8px;
  font-size: 14px; line-height: 14px; color: var(--text-muted);
  padding: 1px 6px 3px 6px; border-radius: 4px; opacity: 0;
  transition: opacity 0.15s;
}
.stat-tile:hover .tile-add { opacity: 1; }
.tile-add:hover { background: var(--accent-light); color: var(--accent-hover); }

.type-gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; }
.type-card {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px 13px; cursor: pointer; transition: all 0.15s;
  background: var(--bg-primary);
}
.type-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); }
.tc-glyph { font-size: 17px; color: var(--accent); line-height: 1; }
.tc-label { font-size: 13px; font-weight: 600; margin-top: 7px; }
.tc-hint { font-size: 11.5px; color: var(--text-muted); margin-top: 3px; line-height: 1.5; }

.pick-dash { display: flex; flex-direction: column; }
.pd-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 12px; border: 1px solid var(--border-light); border-radius: var(--radius);
  margin-bottom: 8px; cursor: pointer; transition: all 0.15s;
}
.pd-row:hover { border-color: var(--accent); background: var(--bg-tertiary); }
.pd-row.new { border-style: dashed; }
.pd-name { font-size: 13px; font-weight: 600; }
.pd-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }
.pd-go { margin-left: auto; font-size: 11.5px; color: var(--accent); font-weight: 600; }

/* ==========================================================================
   People, grants and the access matrix
   ========================================================================== */

.ava {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
  background: var(--accent-light); color: var(--accent-hover);
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.2px;
  vertical-align: middle; margin-right: 4px;
}
/* Outside the firm is the one axis these screens are about, so it is what
   --hi gets spent on here. Nothing else on the page is orange. */
.ava.ext { background: var(--hi-soft); color: var(--hi); }

.role-pill {
  display: inline-flex; align-items: center;
  font-size: 10.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.4px; padding: 2px 0; border-radius: 4px; white-space: nowrap;
}
/* One color axis on this page, and it is the one that matters: inside the firm
 * against outside it. Role is a rank, so it reads as a rank, in weight and in
 * one gray ramp, rather than as four more hues competing for the same glance. */
.role-pill.r-resource_owner { background: none; color: var(--text-primary); font-weight: 700; }
.role-pill.r-contributor { background: none; color: var(--text-secondary); }
.role-pill.r-viewer { background: none; color: var(--text-muted); }
.role-pill.r-org { background: none; color: var(--text-secondary); }
.role-pill.r-invited { background: none; color: var(--text-muted); }
.role-pill.r-external { background: var(--hi-soft); color: var(--hi);
  padding: 2px 8px; font-weight: 700; }

.expiry { font-variant-numeric: tabular-nums; }
.expiry .exp-left { color: var(--text-muted); }
.expiry.soon, .expiry.soon .exp-left { color: var(--red-dark); font-weight: 600; }
.expiry.gone, .expiry.gone .exp-left { color: var(--text-muted); }

.scope-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; color: var(--text-primary);
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-radius: 5px; padding: 2px 7px; white-space: nowrap; margin-right: 3px;
}
.scope-chip.dead { opacity: 0.5; text-decoration: line-through; }
.scope-chip i {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 3px; font-style: normal;
  font-size: 9px; font-weight: 700; color: #fff;
}
/* The letter already says which level of the tree this is. Three more hues
 * behind it said nothing the letter did not. */
.scope-chip i.st-client { background: var(--text-secondary); }
.scope-chip i.st-site { background: var(--text-muted); }
.scope-chip i.st-station { background: #a9b8c8; }

.mono-chip {
  font-family: var(--mono); font-size: 11px;
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-radius: 4px; padding: 1px 6px; color: var(--text-secondary);
}
tr.dead-row td { opacity: 0.55; }

.matrix-wrap { overflow-x: auto; }
table.mx { border-collapse: collapse; font-size: 12px; }
table.mx th, table.mx td { border-bottom: 1px solid var(--border-light); }
table.mx th.mx-name, table.mx td.mx-name {
  position: sticky; left: 0; z-index: 2;
  background: var(--bg-primary); text-align: left;
  padding: 7px 12px; white-space: nowrap; min-width: 210px;
  border-right: 1px solid var(--border);
}
table.mx thead th { background: var(--bg-secondary); vertical-align: bottom; }
table.mx thead th.mx-name { background: var(--bg-secondary); }
table.mx th.mx-col { padding: 8px 0; width: 30px; }
table.mx th.mx-col span {
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-size: 10.5px; font-weight: 600; color: var(--text-secondary);
  white-space: nowrap; max-height: 130px; overflow: hidden;
}
table.mx td.mx-cell { text-align: center; padding: 4px 2px; }
table.mx tbody tr:hover td { background: var(--bg-tertiary); }
table.mx tbody tr:hover td.mx-name { background: var(--bg-tertiary); }
table.mx tbody tr.clickable { cursor: pointer; }
.mx-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 20px; border-radius: 4px;
  font-size: 10px; font-weight: 700; color: #fff;
}
.mx-mark.m-resource_owner { background: var(--navy); }
.mx-mark.m-contributor { background: var(--blue); }
.mx-mark.m-viewer { background: var(--sky); }
.mx-mark.m-part {
  background: repeating-linear-gradient(135deg, var(--text-muted), var(--text-muted) 3px, #c6d2df 3px, #c6d2df 6px);
}
.mx-mark.m-none { background: var(--bg-secondary); border: 1px solid var(--border-light); }
.heat-legend i.mx-mark { width: 18px; height: 16px; font-size: 9px; }
table.mx th.mx-tot, table.mx td.mx-tot {
  text-align: right; padding: 6px 12px; font-variant-numeric: tabular-nums;
  color: var(--text-secondary); font-size: 11.5px; white-space: nowrap;
}
.mx-ext {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  background: var(--hi-soft); color: var(--hi);
  padding: 1px 5px; border-radius: 3px; margin-left: 6px;
}

/* -------------------------------------------------------- clients and sites */

.org-node {
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  margin-bottom: 10px; overflow: hidden;
}
.org-row {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; cursor: pointer; font-size: 13px;
  border-top: 1px solid var(--border-light);
}
.org-row:first-child { border-top: none; }
.org-row:hover { background: var(--bg-tertiary); }
.org-row.client { font-weight: 600; }
.org-row.site { padding-left: 26px; background: var(--bg-secondary); }
.org-row.station { padding-left: 42px; font-size: 12.5px; }
.org-caret { width: 12px; color: var(--text-muted); font-size: 10px; flex-shrink: 0; }
.org-name { min-width: 170px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.org-meta { font-size: 11.5px; color: var(--text-muted); font-weight: 400; white-space: nowrap; }
.org-meta b { color: var(--text-secondary); }
.org-people {
  margin-left: auto; font-size: 11.5px; color: var(--text-secondary);
  font-weight: 500; white-space: nowrap;
}
.org-row .btn { padding: 3px 10px; font-size: 11.5px; flex-shrink: 0; }
.org-body { padding: 12px 14px 14px 32px; border-top: 1px solid var(--border-light); }
.org-body.sub { padding: 10px 0 10px 20px; }

/* The tree already says what a node is by where it sits and how far it is
 * indented. Three badge colors on top of that was decoration, not structure. */
.org-kind {
  font-size: 10px; font-weight: 600; letter-spacing: 0.4px;
  text-transform: uppercase; color: var(--text-muted);
  width: 52px; flex-shrink: 0;
}

.acc-panel {
  border: 1px solid var(--border-light); border-radius: var(--radius);
  background: var(--bg-secondary); margin-bottom: 12px; overflow: hidden;
}
.acc-head {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted);
  border-bottom: 1px solid var(--border-light);
}
.acc-head span { margin-left: auto; }
.acc-empty { padding: 12px; font-size: 12px; color: var(--text-muted); line-height: 1.55; }
.acc-panel table.dt { background: var(--bg-primary); }
.acc-panel table.dt td { padding: 7px 12px; }
.acc-foot {
  padding: 8px 12px; font-size: 11.5px; color: var(--text-muted);
  border-top: 1px solid var(--border-light);
}
.pin-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 0; font-size: 12.5px;
}

/* A twelve column grid on a phone is not a grid. Below the sidebar breakpoint
   every widget goes full width and keeps its own height. */
@media (max-width: 900px) {
  .dash-grid .w { grid-column: span 12 !important; }
  .f-row { flex-direction: column; gap: 4px; }
  .f-label { width: auto; padding-top: 0; }
  .org-row { flex-wrap: wrap; }
  .org-people { margin-left: 0; }
}

/* ---------------------------------------------------------------- Cx actions

   Fix and Review are the two dispositions every Cx action carries, and they
   are not a severity: a P1 can be a review and a P3 can be a fix. So they get
   their own shape, an outlined chip, and stay out of the red/amber/green the
   severity pills own. Blue is "somebody can go do this", violet is "somebody
   has to decide first". Grey is a row held off the punch list entirely.       */

.disp {
  display: inline-flex; align-items: center;
  font-size: 11px; letter-spacing: 0.3px; white-space: nowrap;
}
/* Fix is the one somebody can be sent to do today, so it carries the weight.
   Review stays quiet on purpose. Same treatment as .qr-disp on a quiet row. */
.disp.fix { color: var(--text-secondary); font-weight: 600; }
.disp.review { color: var(--text-muted); }
.disp.held { color: var(--text-muted); font-style: italic; }

/* A held point either releases itself at a time or it does not release at all.
   Both are facts about one column, so both read as words. The list is already
   titled Permanent; a red badge on all 48 rows of it said nothing. */
.ovr-never { font-size: 11.5px; color: var(--text-secondary); font-weight: 600; }
.ovr-at { font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* The filter chips keep the one accent every other chip in the app uses, so a
   chip means the same thing on every screen. */
.chip.disp-fix, .chip.disp-review { font-weight: 600; }

/* The fix guidance under a punch-list row. Same text the report prints, so a
   row read here and a row read in the document say the same thing. */
.punch-do {
  font-size: 11px; color: var(--text-secondary);
  margin-top: 3px; line-height: 1.45; max-width: 460px;
}
.punch-do b { color: var(--text-primary); font-weight: 600; }

table.dt.punch td { vertical-align: top; }
table.dt td.wrap {
  white-space: normal; word-break: break-all; max-width: 300px;
}
tr.group-row .disp { margin-left: 8px; }

.cs-mark {
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.4px;
  background: var(--orange-light); color: var(--orange);
  padding: 1px 4px; border-radius: 3px; vertical-align: middle;
}

/* --------------------------------------------------------------- Cx reports */

/* Status marks are the report's own four: error, warning, info, pass, plus an
   open circle for an analysis that did not run. An analysis that was skipped
   must never draw as a pass. */
.sicon { font-size: 13px; line-height: 1; }
.sicon.err { color: var(--red-dark); }
.sicon.warn { color: var(--orange); }
.sicon.ok { color: var(--green-dark); }
.sicon.info { color: var(--text-muted); }
.sicon.skip { color: var(--text-muted); }

.sec-strip { white-space: nowrap; }
.sdot {
  display: inline-block; width: 9px; height: 9px; border-radius: 2px;
  margin-right: 3px; vertical-align: middle;
}
.sdot.error { background: var(--red); }
.sdot.warn { background: var(--orange); }
.sdot.pass { background: var(--green); }
.sdot.info { background: #c6d2df; }
.sdot.skipped { background: transparent; border: 1px dashed var(--text-muted); }
.gap-flag {
  margin-left: 6px; font-size: 10px; font-weight: 700; letter-spacing: 0.3px;
  background: var(--orange-light); color: var(--orange);
  padding: 1px 5px; border-radius: 3px;
}

.rep-mast {
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-top: 3px solid var(--navy);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: 16px 18px; margin-bottom: 14px;
}
.rep-mast-top { display: flex; align-items: flex-start; gap: 12px; }
.rep-kicker {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.7px;
  text-transform: uppercase; color: var(--text-muted);
}
.rep-title { font-size: 21px; font-weight: 700; letter-spacing: -0.2px; margin-top: 2px; }
.rep-where { font-size: 12.5px; color: var(--text-secondary); }

.rep-note {
  font-size: 12px; line-height: 1.55; padding: 9px 13px; margin-bottom: 14px;
  border-radius: var(--radius); border: 1px solid var(--border-light);
  background: var(--bg-primary); color: var(--text-secondary);
}
.rep-note.cs { background: var(--orange-light); border-color: #efdaac; color: var(--orange); }
.rep-note.stale { background: var(--red-light); border-color: #f0c2ce; color: var(--red-dark); }
.rep-note b { color: inherit; }

.gap-row {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: 12px; color: var(--text-secondary); line-height: 1.5;
  padding: 7px 0; border-bottom: 1px solid var(--border-light);
}
.gap-row:last-child { border-bottom: none; }
.gap-row b { color: var(--text-primary); font-size: 12.5px; }

/* One block per analysis, in the order the document prints them. */
.rep-sec { margin: 22px 0 18px 0; scroll-margin-top: 16px; }
.rep-sec-head {
  display: flex; align-items: flex-start; gap: 10px;
  padding-bottom: 8px; margin-bottom: 10px;
  border-bottom: 2px solid var(--border);
}
.rep-sec-title { font-size: 16px; font-weight: 700; letter-spacing: -0.1px; }
.rep-sec-sub { font-size: 12px; color: var(--text-secondary); margin-top: 1px; }
.rep-sec-right {
  margin-left: auto; display: flex; align-items: center; gap: 8px;
  flex-shrink: 0; padding-top: 2px;
}

.rep-subs {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  font-size: 11.5px; color: var(--text-muted); margin-bottom: 10px;
}
.rep-subs span {
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-radius: 4px; padding: 1px 7px; color: var(--text-secondary);
}

.rep-pass, .rep-skip {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--text-secondary); line-height: 1.5;
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius); padding: 11px 14px;
}
.rep-skip { background: var(--bg-secondary); border-style: dashed; }

.btn.sm { padding: 3px 9px; font-size: 11.5px; }


/* ==========================================================================
 * Quiet rows.
 *
 * One color axis per screen, one line per item, prose behind a disclosure.
 * The tier stripe on the section is the only color the feed and the punchlist
 * spend. Kind is a monochrome three letter code in a fixed column, so the
 * codes line up down the page instead of scattering twelve hues across it.
 * Everything a card used to show at once now waits inside the open row.
 * ======================================================================== */

.qsec {
  display: flex; align-items: baseline; gap: 9px;
  margin: 20px 0 7px 0; padding-left: 11px;
  border-left: 3px solid var(--border);
}
.qsec:first-child { margin-top: 2px; }
.qsec.t1 { border-left-color: var(--red); }
.qsec.t2 { border-left-color: var(--orange); }
.qsec-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.7px;
  text-transform: uppercase; color: var(--text-secondary);
}
.qsec.t1 .qsec-label { color: var(--red-dark); }
.qsec-count {
  font-size: 11px; font-weight: 700; color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.qsec-sub { font-size: 11.5px; color: var(--text-muted); }
.qsec-right { margin-left: auto; font-size: 11.5px; color: var(--text-muted); }

.qlist {
  background: var(--bg-primary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  overflow: hidden;
}

.qrow {
  display: grid;
  align-items: baseline;
  gap: 10px;
  padding: 8px 14px;
  font-size: 13px;
  cursor: pointer;
  border-top: 1px solid var(--border-light);
}
/* caret, code, title, station, who, age, disposition */
.qlist.feed .qrow { grid-template-columns: 15px 40px minmax(0, 1fr) 186px 78px 40px 54px; }
/* caret, check code, title, station, disposition */
.qlist.punch .qrow { grid-template-columns: 15px 98px minmax(0, 1fr) 168px 52px; }
/* caret, rule id, what it catches, tier, fires, state */
.qlist.rules .qrow { grid-template-columns: 15px 176px minmax(0, 1fr) 78px 62px 74px; }
.qrow:first-child { border-top: 0; }
.qrow:hover { background: var(--bg-secondary); }
.qrow.open { background: var(--bg-secondary); }

.qr-caret {
  font-size: 10px; color: var(--text-secondary); line-height: 1.6;
  transition: transform 0.12s ease; transform-origin: 40% 55%;
}
.qrow.open .qr-caret { transform: rotate(90deg); color: var(--text-secondary); }

.qr-code {
  font-family: var(--mono); font-size: 10px; font-weight: 600;
  letter-spacing: 0.3px; color: var(--text-muted);
  background: var(--bg-secondary); border-radius: 3px;
  padding: 2px 0; text-align: center;
  white-space: nowrap; overflow: hidden;
}
.qrow.open .qr-code, .qrow:hover .qr-code { background: var(--bg-tertiary); }

.qr-title {
  font-weight: 500; color: var(--text-primary); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.qr-where, .qr-who, .qr-when {
  font-size: 11.5px; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.qr-when { text-align: right; font-variant-numeric: tabular-nums; }
.qr-where b { font-weight: 500; color: var(--text-secondary); }

/* Disposition is a word, not a badge. Fix is the one somebody can be sent to
 * do today, so it carries the weight; review stays quiet on purpose. */
.qr-disp { font-size: 11px; letter-spacing: 0.3px; text-align: right; }
.qr-disp.fix { color: var(--text-secondary); font-weight: 600; }
.qr-disp.review { color: var(--text-muted); }

.qr-flag { color: var(--red-dark); font-weight: 600; }

.qbody {
  padding: 2px 14px 14px 80px;
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-light);
  font-size: 12.5px; color: var(--text-secondary); line-height: 1.55;
}
.qbody > div + div { margin-top: 9px; }
.qb-detail { color: var(--text-secondary); }
.qb-line b {
  display: inline-block; min-width: 52px;
  color: var(--text-primary); font-weight: 600;
}
.qb-meta { font-size: 11.5px; color: var(--text-muted); }
.qb-meta .st-name { color: var(--accent); cursor: pointer;
  font-size: inherit; font-weight: 500; letter-spacing: 0; }
.qb-meta .st-name:hover { text-decoration: underline; }
.qb-ev {
  font-family: var(--mono); font-size: 11px; color: var(--text-secondary);
  background: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: 5px; padding: 8px 10px; line-height: 1.6;
}
.qb-actions { display: flex; gap: 7px; flex-wrap: wrap; }
.qbody .f-hint { max-width: 88ch; }
.qbody .f-row { padding: 10px 0; }
.qbody .f-row:first-of-type { border-top: 1px solid var(--border-light); margin-top: 4px; }

.qmore { padding: 8px 14px; font-size: 11.5px; color: var(--text-muted);
  border-top: 1px solid var(--border-light); }

/* Only where the columns do not name themselves. A feed row is a sentence;
 * a rule row is a record, and a record wants headings. */
.qhead {
  display: grid; gap: 10px; padding: 7px 14px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-light);
  font-size: 10px; font-weight: 700; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--text-muted);
}
.qlist.rules .qhead { grid-template-columns: 15px 176px minmax(0, 1fr) 78px 62px 74px; }
.qhead .r { text-align: right; }

/* One disclosure per screen instead of a paragraph under every heading. */
.qnote { margin: 10px 0 0 0; font-size: 12px; }
.qnote > summary {
  cursor: pointer; color: var(--text-muted); font-size: 11.5px;
  list-style: none; display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 0; user-select: none;
}
.qnote > summary::-webkit-details-marker { display: none; }
.qnote > summary::before { content: "?"; font-size: 9px; font-weight: 700;
  width: 13px; height: 13px; border-radius: 50%; flex-shrink: 0;
  border: 1px solid var(--border); color: var(--text-muted);
  display: inline-flex; align-items: center; justify-content: center; }
.qnote > summary:hover { color: var(--accent); }
.qnote > summary:hover::before { border-color: var(--accent); color: var(--accent); }
.qnote[open] > summary { color: var(--text-secondary); margin-bottom: 6px; }
.qnote-body {
  color: var(--text-secondary); font-size: 12px; line-height: 1.6;
  border-left: 2px solid var(--border-light); padding: 2px 0 2px 11px;
  max-width: 74ch;
}
.qnote-body p + p { margin-top: 6px; }
.qnote-body b { color: var(--text-primary); font-weight: 600; }

/* The extra filter dimensions fold away. The page opens on the axis people
 * actually triage by and keeps the rest one click out. */
.qfold { display: inline-flex; align-items: center; gap: 5px; }
.qfold-btn {
  font-size: 11.5px; color: var(--text-secondary); cursor: pointer;
  border: 1px dashed var(--border); border-radius: 20px;
  padding: 3px 11px; background: none; user-select: none;
}
.qfold-btn:hover { border-color: var(--accent); color: var(--accent); }
.qfold-btn.on { border-style: solid; border-color: var(--accent);
  color: var(--accent); background: var(--accent-light); }


/* ------------------------------------------------------------------ rules */

.qr-rule {
  font-family: var(--mono); font-size: 11px; color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.qr-state { text-align: right; }
.qrow.dim-row .qr-rule, .qrow.dim-row .qr-title { opacity: 0.55; }

/* State is a word in one weight. Off is the only one that gets a color,
 * because off is the only one that changes what the fleet is watching for. */
.rstate {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.3px;
  padding: 1px 7px; border-radius: 10px; white-space: nowrap;
}
.rstate.on { color: var(--text-muted); background: var(--bg-secondary); }
.rstate.muted { color: var(--text-secondary); background: var(--bg-tertiary); }
.rstate.tuned { color: var(--text-secondary); background: var(--bg-tertiary); }
.rstate.off { color: var(--red-dark); background: var(--red-light); }

.mute-row {
  display: grid;
  grid-template-columns: minmax(0, 220px) minmax(0, 1fr) 156px 118px 52px;
  gap: 10px; align-items: baseline;
  padding: 8px 14px; font-size: 12.5px;
  border-top: 1px solid var(--border-light);
}
.mute-row:first-child { border-top: 0; }
.mute-what { font-weight: 500; }
.mute-what .st-name { color: var(--accent); cursor: pointer;
  font-size: inherit; font-weight: 500; letter-spacing: 0; }
.mute-what .st-name:hover { text-decoration: underline; }
.mute-why { color: var(--text-secondary); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.mute-when { font-size: 11.5px; color: var(--text-muted);
  font-variant-numeric: tabular-nums; }
.mute-when.soon { color: var(--red-dark); font-weight: 600; }
.mute-by { font-size: 11.5px; color: var(--text-muted); }

.f-input.thr { width: 92px; }
.thr-unit { font-size: 12px; color: var(--text-secondary); margin-left: 6px; }

@media (max-width: 1180px) {
  .qlist.feed .qrow { grid-template-columns: 15px 40px minmax(0, 1fr) 108px 52px; }
  .qlist.feed .qr-who, .qlist.feed .qr-when { display: none; }
  .qlist.rules .qrow { grid-template-columns: 15px 150px minmax(0, 1fr) 62px 74px; }
  .qlist.rules .qr-when { display: none; }
  .mute-row { grid-template-columns: minmax(0, 1fr) 118px 52px; }
  .mute-why, .mute-by { display: none; }
}


/* ==========================================================================
 * Sidebar: folding sections and the collapsed rail.
 *
 * Same doctrine as the feed. A heading says what is under it and how much;
 * the list itself waits until somebody wants it. The rail takes that one step
 * further and keeps only the glyphs, for whoever is working in the tables and
 * wants the width back.
 * ======================================================================== */

.sidebar { transition: width 0.18s ease; }
.main { transition: left 0.18s ease, right 0.25s; }

/* One variable moves both. */
body.rail { --sidebar-w: 58px; }
body.rail .sidebar { padding: 10px 0 0 0; overflow-x: hidden; }

.sidebar-heading.fold {
  display: flex; align-items: center; gap: 5px;
  cursor: pointer; user-select: none;
  padding: 3px 6px; margin: 0 -6px 5px -6px;
  border-radius: 5px;
}
.sidebar-heading.fold:hover { background: var(--bg-secondary); color: var(--text-secondary); }
.fold-caret {
  font-size: 8px; width: 9px; flex-shrink: 0; color: var(--text-secondary);
  transition: transform 0.14s ease; transform-origin: 45% 55%;
}
.sidebar-heading.fold.off .fold-caret { transform: rotate(-90deg); }
.fold-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Folded scope still says what it is doing to the numbers on screen. */
.scope-summary {
  font-size: 11.5px; color: var(--text-secondary); line-height: 1.5;
  padding: 0 6px 2px 20px; margin: -3px 0 4px 0; cursor: pointer;
}
.scope-summary:hover { color: var(--accent); }

.nav-item.recent .nav-glyph { font-size: 10px; opacity: 0.6; }

/* Saved views sit inside Dashboards under their own quiet label, so one group
   can hold two kinds of prepared way in without pretending they are the same. */
.nav-sub {
  font-size: 10px; font-weight: 700; letter-spacing: 0.5px;
  text-transform: uppercase; color: var(--text-muted);
  padding: 10px 11px 3px 11px;
}

/* The pin appears on hover, stays once it is set. Nothing on a resting row
   until somebody reaches for it. */
.nav-pin {
  margin-left: 6px; font-size: 9px; color: var(--text-muted);
  opacity: 0; transition: opacity 0.12s, color 0.12s; flex-shrink: 0;
  width: 12px; text-align: center;
}
.nav-item.recent:hover .nav-pin { opacity: 1; }
.nav-item.recent.pinned .nav-pin { opacity: 1; color: var(--accent); }
.nav-pin:hover { color: var(--accent); }
.nav-item.recent .nav-count + .nav-pin { margin-left: 6px; }
.nav-item.recent .nav-label { flex: 1; }

/* ------------------------------------------------------------ account menu */

.acct-wrap { position: relative; }
.avatar.on { box-shadow: 0 0 0 2px var(--accent-light); }
.acct-menu {
  position: absolute; top: 44px; right: 0; width: 268px;
  background: var(--bg-primary); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  overflow: hidden; z-index: 120;
}
.acct-menu:empty { display: none; }
.acct-head { padding: 13px 14px; border-bottom: 1px solid var(--border-light); }
.acct-name { font-size: 13.5px; font-weight: 700; }
.acct-mail { font-size: 11.5px; color: var(--text-secondary); margin-top: 1px; }
.acct-org { font-size: 11px; color: var(--text-muted); margin-top: 4px; }
.acct-sec { padding: 11px 14px; border-bottom: 1px solid var(--border-light); }
.acct-sec:last-child { border-bottom: 0; padding: 6px 6px; }
.acct-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.5px;
  text-transform: uppercase; color: var(--text-secondary); margin-bottom: 7px;
}
.acct-hint { font-size: 11px; color: var(--text-muted); margin-top: 7px; line-height: 1.5; }
.acct-row {
  padding: 7px 8px; border-radius: 6px; font-size: 12.5px;
  color: var(--text-secondary); cursor: pointer;
}
.acct-row:hover { background: var(--bg-tertiary); color: var(--accent-hover); }

/* ------------------------------------------------------------- the toggle */

/* Expanded, the collapse control is one of the tools in the Views heading.
   Collapsed, there is no heading left to hang it on, so it leads the rail. */
.rail-toggle {
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 2px auto; width: 38px; height: 30px;
  border-radius: 7px; cursor: pointer; user-select: none;
  color: var(--text-secondary);
}
.rail-toggle:hover { background: var(--bg-tertiary); color: var(--accent); }
.rail-caret { font-size: 17px; font-weight: 700; }
.nav-tool.rail-tool { font-size: 17px; line-height: 14px; padding: 1px 6px 3px 6px; }

/* ---------------------------------------------------------------- the rail */

.rail-list { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.rail-item {
  position: relative;
  width: 38px; height: 34px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-secondary);
  transition: background 0.15s, color 0.15s;
}
.rail-item:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.rail-item.active { background: var(--accent-light); color: var(--accent-hover); }
.rail-item .nav-glyph { width: auto; font-size: 14px; opacity: 1; }
.rail-dot {
  position: absolute; top: 6px; right: 6px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--red); box-shadow: 0 0 0 2px var(--bg-primary);
}
.rail-initials {
  font-size: 10px; font-weight: 700; letter-spacing: 0.2px;
  color: var(--text-secondary);
}
.rail-item.active .rail-initials { color: var(--accent-hover); }
.rail-sep { height: 1px; background: var(--border-light); margin: 6px 12px; }


/* ==========================================================================
 * Type.
 *
 * Barlow Condensed does the label work: page and section titles, and every
 * uppercase micro-label down to the badges. Running text stays Barlow.
 *
 * This block sits at the end of the file on purpose. Nearly every selector in
 * it sets its own font-size and letter-spacing further up, and an equally
 * specific rule declared earlier loses. Put this near the tokens instead and
 * only the font-family lands, which is how it reads at first and why it is
 * worth a comment: the sizes silently do nothing.
 *
 * Condensed sets about a size smaller than Barlow at the same px, and these
 * labels were already at the floor, so they get a point back and the tracking
 * opens toward the brand's .14em.
 * ======================================================================== */

/* .st-name is scoped to the station header. The same class is reused inline
   inside a sentence on a quiet row and in the mute list, where a condensed
   26 px station name would be wrong; those rules pin size and weight but not
   family, so an unscoped selector here would reach them. */
.page-title, .st-header .st-name, .rep-title, .dash-name {
  font-family: var(--cond); font-size: 26px; font-weight: 600; letter-spacing: 0;
}
.rep-sec-title { font-family: var(--cond); font-size: 19px; letter-spacing: 0; }
.modal-title { font-family: var(--cond); font-size: 17px; letter-spacing: 0; }
.acct-name { font-family: var(--cond); font-size: 16px; letter-spacing: 0; }
.topnav-title { font-family: var(--cond); }

.sidebar-heading, .stat-label, .acct-label, .nav-sub, .pick-head, .acc-head,
.qsec-label, .rep-kicker, .org-kind, .att-tier, .role-pill, .qhead,
.heat th, .rstate, .mx-ext, .cs-mark, .gap-flag, .dev-badge, .chip.prio,
table.dt th, table.mx thead th, .pill, .tag {
  font-family: var(--cond);
}
.stat-label, table.dt th, .qhead, .qsec-label, .rep-kicker,
.acct-label, .nav-sub, .pick-head, .acc-head, .org-kind {
  font-size: 11.5px; letter-spacing: 0.09em;
}
/* Every section title in the sidebar, one size: WATCH, INVESTIGATE and
   RECENT all read as the same rank, and they were set smaller than the nav
   items sitting under them. Condensed caps read light for their size, so 14px
   here sits at about the 13px of a nav item and still stays quieter than it.
   The nested Saved views label keeps its own smaller size, so the level under
   a group still separates. */
.sidebar-heading { font-size: 14px; letter-spacing: 0.07em; }
.pill, .tag, .att-tier, .role-pill, .rstate, .mx-ext, .cs-mark, .gap-flag {
  font-size: 11px; letter-spacing: 0.06em;
}


/* ==========================================================================
 * The vendor credit, at the foot of the sidebar. It links to buildinglogix.net.
 *
 * The mark in the top nav is the product, StationCx. This is the firm that
 * makes it, and two of the brand's rules still bind here: the mark is the
 * shipped glyph, arch and nine window squares, never a silhouette of it, and
 * the name is set in Arial Black.
 *
 * The colour rule does not. "The wordmark is always two colors, Building in
 * blue and LogiX in orange" governs the corporate wordmark standing on its
 * own. A "Powered by" endorsement is a different usage and the firm ships that
 * badge in a single colour, so this is navy throughout, mark and text, the
 * text taking its ink from the mark. That also gets --hi off the shell:
 * orange is THE highlight, spent once on the thing a screen is about, and a
 * vendor credit is never that.
 * ======================================================================== */

.blx-foot {
  margin-top: auto;
  display: flex; align-items: center; gap: 9px;
  padding: 14px 16px 6px 16px;
  border-top: 1px solid var(--border-light);
  color: var(--navy); text-decoration: none;
  opacity: 0.82; transition: opacity 0.15s;
}
.blx-foot:hover { opacity: 1; }
.blx-foot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* 20px, not 13px. Each window is 4.03 of the glyph's 33.76 units. Rendered
   down a ladder at 1x, 13px loses the top two rows of windows to a haze, 18px
   is where all three rows come back, and 20px is where the nine of them are
   clean. Below that you are shipping a silhouette, which is what used to be
   here. The deck sets this lockup at a 22px mark over an 18px wordmark; this
   is 20 over 14, one step quieter because it is chrome. */
.blx-foot svg { height: 20px; width: auto; fill: currentColor; flex-shrink: 0; }
.blx-word {
  font-family: "Arial Black", "Arial Bold", Arial, Helvetica, sans-serif;
  font-weight: 900; font-size: 13px; line-height: 1;
  letter-spacing: -0.3px; white-space: nowrap; color: currentColor;
}
/* "Powered by" is the credit and not the name, so it is set in the running
   face a size down and stays out of the wordmark's way. Same ink. */
.blx-word i {
  font-family: "Barlow", sans-serif; font-style: normal; font-weight: 500;
  font-size: 11px; letter-spacing: 0;
}

/* Ownership, under the credit. A legal line is not a label: it sits a size
   below the credit, in muted ink, and comes off with the wordmark when the
   sidebar collapses to the rail. */
.blx-legal {
  padding: 0 16px 12px 16px;
  font-size: 10px; line-height: 1.4;
  color: var(--text-muted);
}
body.rail .blx-legal { display: none; }

/* Same line on the sign-in page, which is the one screen a person sees before
   they have any account at all. Centred under the card, not inside it. */
.login-legal {
  margin: 18px 0 0 0; text-align: center;
  font-size: 10px; line-height: 1.4;
  color: var(--text-muted);
}

/* Collapsed to the rail there is no room for a wordmark, so the mark holds the
   floor on its own. */
body.rail .blx-foot { justify-content: center; padding: 14px 0 6px 0; }
body.rail .blx-word { display: none; }

/* ==========================================================================
   Print

   One screen is worth printing: the Cx report, which is the document that goes
   to a customer. Everything that is navigation comes off, and the main column
   stops being a fixed scroll box, because a fixed element prints one screenful
   and drops the rest.

   Disclosures print as they sit. A note somebody left closed is a note they
   did not want, and forcing every one open would put four paragraphs of
   reasoning in the middle of a deliverable.
   ========================================================================== */

@media print {
  .topnav, .sidebar, .chat-panel, .modal-host,
  .page-head-actions, .tabs, .qfold, .fs-clear { display: none !important; }

  .main, .main.chat-open {
    position: static; top: auto; left: auto; right: auto; bottom: 0;
    overflow: visible; transition: none;
  }
  .page { padding: 0; max-width: none; }

  body { background: #fff; }
  .panel {
    box-shadow: none; border: 1px solid #c8ced6;
    break-inside: avoid; page-break-inside: avoid;
  }
  .panel-head { break-after: avoid; page-break-after: avoid; }
  tr, .qrow, .stat-tile { break-inside: avoid; page-break-inside: avoid; }
  .table-wrap, .matrix-wrap { overflow: visible; }
}
/*
 * Copyright (c) 2026 BuildingLogiX. All rights reserved.
 *
 * StationCx. Proprietary and confidential. This source is licensed, not sold.
 * No part of it may be copied, distributed, disclosed or used to produce a
 * derivative work without the prior written permission of BuildingLogiX.
 *
 * Access to the hosted service under a current StationCx agreement does not
 * transfer any right in this source.
 */

/* ------------------------------------------------- portal: boot and states */
/* Added in cloud/web/, not in the mockup. The mockup read a synchronous global
 * and never had a moment where data was missing; the portal fetches it, so
 * loading, failed and signed-out are screens now. */

.boot-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 64px 24px; text-align: center;
}
.boot-spin {
  width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--accent);
  animation: boot-spin 0.8s linear infinite;
}
@keyframes boot-spin { to { transform: rotate(360deg); } }
.boot-text { font-size: 13px; color: var(--text-secondary); }
.boot-state.fail .boot-spin { display: none; }
.boot-title { font-size: 15px; font-weight: 600; }
.boot-detail { font-size: 13px; color: var(--text-secondary); max-width: 560px; }
.boot-req { font-family: var(--mono); font-size: 11px; color: var(--text-muted); }
.boot-actions { display: flex; gap: 8px; margin-top: 6px; }

/* ------------------------------------------------ portal: envelope coverage */
/* metrics.partial rendered next to the number it qualifies. A count that is
 * silently a floor is worse than no count, so the mark and the note ship
 * together and neither one is optional. */

.floor-mark {
  display: inline-block; margin-left: 4px; padding: 0 4px;
  border: 1px solid var(--orange); border-radius: 3px;
  font-size: 9.5px; font-weight: 700; line-height: 14px; letter-spacing: 0.03em;
  color: var(--orange); background: var(--orange-light); vertical-align: 1px;
  text-transform: uppercase;
}
.cov-notes { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.cov-note {
  font-size: 12px; line-height: 1.55; color: var(--text-secondary);
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-left: 3px solid var(--border); border-radius: var(--radius);
  padding: 8px 11px;
}
.cov-note b { color: var(--text-primary); }
.cov-note.warn {
  background: var(--orange-light); border-color: #efdaac; border-left-color: var(--orange);
  color: var(--orange);
}
.cov-note.warn b { color: var(--orange); }
.heat-cell.c-part { background: #b7e4d1; border: 1px solid var(--orange); }

/* ------------------------------------------------------- portal: data source */

.src-pill {
  font-size: 11px; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--border); color: var(--text-secondary); background: var(--bg-primary);
  cursor: pointer;
}
.src-pill:hover { border-color: var(--accent); color: var(--accent); }

/* ------------------------------------------------------------ portal: login */

/* background-color, not the background shorthand: the shorthand resets
 * background-image and took the drafting grid off with it, so you signed
 * in on flat grey and landed on a ruled table. */
body.login-page { overflow: auto; background-color: var(--ground); }
/* Column, not the default row. The legal line is a sibling of the card, not
 * something inside it, and in a row flex the two shared the line: the notice
 * sat out to the right of the card in the middle of the page and shoved the
 * card left of centre. */
.login-wrap {
  min-height: 100vh; display: flex; flex-direction: column;
  align-items: center; justify-content: center; padding: 32px;
}
.login-card {
  width: 100%; max-width: 400px; background: var(--bg-primary);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md); padding: 26px 26px 22px;
}
.login-brand { display: flex; align-items: center; gap: 9px; margin-bottom: 18px; }
.login-h { font-size: 15px; font-weight: 600; margin-bottom: 4px; }
.login-sub { font-size: 12.5px; color: var(--text-secondary); margin-bottom: 16px; line-height: 1.55; }
.login-card .f-input { width: 100%; margin-bottom: 10px; }
.login-card .btn { width: 100%; justify-content: center; }
.login-code { font-family: var(--mono); letter-spacing: 0.3em; text-align: center; font-size: 17px; }
.login-msg { font-size: 12.5px; line-height: 1.55; margin: 10px 0 2px; }
.login-msg.err { color: var(--red-dark); }
.login-msg.ok { color: var(--text-secondary); }
.login-foot {
  margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--border-light);
  font-size: 11.5px; color: var(--text-muted); line-height: 1.6;
}
.login-foot a { color: var(--text-secondary); }
.login-back {
  background: none; border: 0; padding: 0; margin-top: 10px;
  font: inherit; font-size: 12px; color: var(--text-secondary);
  cursor: pointer; text-decoration: underline;
}

/* -------------------------------------------- portal: writing the hierarchy */
/* Clients and sites can be created, renamed and deleted here and cannot be in
 * the mockup, whose generator always wrote six clients. These are the states
 * that only exist once the tree is empty or once a row can be acted on.
 * assets/orgs.js draws them. */

.org-empty { padding: 26px 22px; max-width: 640px; }
.org-empty-title { font-size: 15px; font-weight: 600; margin-bottom: 8px; }
.org-empty-body { font-size: 13px; color: var(--text-secondary); line-height: 1.65; }
.org-empty-steps {
  margin-top: 12px; padding: 9px 12px; border-radius: 6px;
  background: var(--bg-secondary); border-left: 2px solid var(--accent);
  font-size: 12.5px; color: var(--text-secondary); line-height: 1.6;
}
.org-empty-actions { display: flex; gap: 8px; margin-top: 16px; }

/* The row that puts a site under a client. It sits at the bottom of the open
 * client body, where somebody has just read the sites that are already there. */
.org-add {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0 2px; margin-top: 6px;
  border-top: 1px solid var(--border-light);
}
.org-add-note { font-size: 11.5px; color: var(--text-muted); line-height: 1.5; flex: 1; }
.org-add .btn { margin-left: auto; }

/* A site can hold stations this screen cannot list, because the fleet read
 * names the client each station belongs to and not the site. Better said than
 * drawn as an empty site. */
.org-note {
  margin: 8px 0 2px; padding: 8px 11px; border-radius: var(--radius);
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-left: 3px solid var(--border);
  font-size: 11.5px; color: var(--text-secondary); line-height: 1.55;
}

/* A live Ask answer takes a second or two. The placeholder is a real message in
   the thread rather than a spinner over the rail, so the scroll position and
   the message count behave the way they do for a finished answer. */
.chat-wait { color: var(--text-muted); }
.chat-wait i { font-style: normal; animation: chat-dot 1.2s infinite; }
.chat-wait i:nth-child(2) { animation-delay: 0.2s; }
.chat-wait i:nth-child(3) { animation-delay: 0.4s; }
@keyframes chat-dot { 0%, 60%, 100% { opacity: 0.25; } 30% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .chat-wait i { animation: none; opacity: 0.6; }
}
/* Why an answer stopped, when it stopped for a reason other than answering.
   It reads as a label rather than as a citation, because a refusal with a
   source line under it looks like a finding. */
.chat-stop {
  margin-top: 7px; font-size: 11px; font-weight: 600; letter-spacing: 0.02em;
  text-transform: uppercase; color: var(--text-muted);
}

/* The tool line a streamed answer shows while the agent is reading, roadmap
   I1. Sits above the growing text in the same bubble, so a reorder from
   "reading findings" to the answer itself never moves anything else on
   screen. */
.chat-tool {
  font-size: 11px; color: var(--text-muted); margin-bottom: 4px;
}
.chat-tool::before { content: "\25b8 "; }

/* A model answer is drawn from a closed set of constructs: paragraphs, a small
   table, bullets, a numbered list, a short heading and the occasional fenced
   block. Everything else arrives as characters, so there is nothing else to
   style. See assets/asklive.js. */
.chat-bubble .chat-h {
  font-weight: 600; font-size: 12.5px; margin: 10px 0 4px;
  color: var(--text-primary);
}
.chat-bubble .chat-h:first-child { margin-top: 0; }
.chat-bubble ul, .chat-bubble ol { margin: 6px 0 6px 18px; padding: 0; }
.chat-bubble li { margin: 2px 0; }
.chat-bubble pre {
  margin: 8px 0; padding: 8px 10px; overflow-x: auto;
  background: var(--bg-tertiary); border: 1px solid var(--border-light);
  border-radius: var(--radius);
}
.chat-bubble pre code { background: none; border: 0; padding: 0; font-size: 11.5px; }

/* The service state, at the foot of the sidebar, from GET /v1/health.

   It sits above the legal line and below the credit, in the chrome, because it
   is a state and not a control. One colour axis: ok is muted like everything
   else around it, and the only thing worth an accent is the case where the web
   role cannot reach the store, because a portal in that state does not look
   broken. The already-loaded screen keeps drawing and the numbers stop moving.

   Collapsed to the rail it comes off with the wordmark. There is no room, and
   the state is the same on the next screen out. See assets/live.js. */
.svc-line {
  padding: 0 16px 6px 16px;
  font-size: 10.5px; line-height: 1.4;
  color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.svc-line.svc-bad { color: var(--red); font-weight: 600; }
body.rail .svc-line { display: none; }


/* Rule configuration against the server. assets/rulesapi.js.

   One colour axis, the same one everything else here uses: nothing is coloured
   except the two states worth noticing, a write that did not land and a host
   the cross-check flagged. Everything else is the muted grey the rest of the
   screen is in, because twenty rows of coloured provenance is the density this
   product deliberately does not have. */

/* A write that did not land. It stays until the next one does, rather than
   fading: a rule switch that silently failed to save is the failure this whole
   block exists to make visible. */
.rule-fail {
  margin: 10px 0; padding: 10px 12px;
  background: var(--red-light); border: 1px solid #ecb4c2;
  border-radius: var(--radius);
  font-size: 12px; line-height: 1.5; color: var(--red-dark);
}
.rule-fail .mono-chip { color: var(--red-dark); }

/* And one that did, saying which envelope it applies from. Not an accent: a
   save that worked is the expected case. */
.rule-applied {
  margin: 10px 0; padding: 8px 12px;
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-radius: var(--radius);
  font-size: 12px; line-height: 1.5; color: var(--text-secondary);
}

/* One threshold: the key, the box, where the value came from, and what the
   shipped value is. One line each, so a rule with three numbers reads as three
   lines rather than a grid. */
.thr-line {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 6px;
}
.thr-line:last-of-type { margin-bottom: 0; }
.thr-from { font-size: 11.5px; color: var(--text-secondary); }
.thr-shipped, .thr-moved { font-size: 11px; color: var(--text-muted); }
.thr-moved { font-weight: 600; }
.f-input.thr.narrow { width: 74px; }

/* The station Rules tab puts a number editor inside a table cell. */
table.dt .f-input.thr { margin: 2px 0; }

/* A cross-check flag on the station header. Evidence against the inferred host
   class, never a different class, so it is a mark next to the chip rather than
   anything that changes what the chip says. */
.meta-chip.flagged { color: var(--red-dark); border-color: #ecb4c2; }
.meta-chip.flagged b { color: var(--red-dark); }

/* A disabled account, beside the invited pill. Same axis: it is a state
   somebody set on purpose, and the grants under it are still on the record. */
.role-pill.r-off { background: var(--red-light); color: var(--red-dark); }

/* ---- host replacement, roadmap B6 --------------------------------------

   The candidate picker in the claim dialog. One row per station this host
   could be replacing, one line of prose each, and no colour on the top score:
   a backup restored onto a bench JACE ranks exactly as high as a genuine
   hardware swap, so an accent on the leader would be the screen making the
   decision this route deliberately does not make. */
.cand-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.cand-row {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 8px 10px; border: 1px solid var(--border-light);
  border-radius: var(--radius); cursor: pointer;
}
.cand-row:hover { background: var(--bg-secondary); }
.cand-row.on { border-color: var(--accent); background: var(--bg-secondary); }
.cand-row input { margin-top: 2px; }
.cand-body { display: block; }
.cand-line { display: block; font-size: 12.5px; line-height: 1.5; }
.cand-sub {
  display: block; font-size: 11px; color: var(--text-muted); margin-top: 2px;
  font-family: ui-monospace, Consolas, monospace;
}

/* The detach control under the station header. One dim line: it is rare, it is
   destructive in the routing sense and in no other, and it must not compete
   with the coverage note above it. */
.host-admin {
  margin-top: 10px; font-size: 11.5px; color: var(--text-secondary);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.host-admin .mono { font-family: ui-monospace, Consolas, monospace; }

/* ---- enrolment codes, roadmap B5 ---------------------------------------

   Eight characters, read off a screen or said down a phone. Big, spaced and
   monospace for exactly that reason, and shown once. */
.enrol-code {
  font-family: ui-monospace, Consolas, monospace;
  font-size: 30px; font-weight: 700; letter-spacing: 5px;
  padding: 16px 12px; text-align: center;
  background: var(--bg-secondary); border: 1px solid var(--border-light);
  border-radius: var(--radius);
}
.enrol-code-actions {
  display: flex; align-items: center; gap: 10px; margin-top: 10px;
  font-size: 12px;
}
