/* Minimal, accessible defaults. Designed for one-pager dashboards. */

/* Ravago brand palette
 * - Primary blue from the logo (~#1F4FB8) — used for headings, links, accent rings.
 * - Orange accent (~#E87722) — used sparingly for "update / live write" CTAs (parallels
 *   ravago.com where the active nav item is rendered in this orange).
 * - Light surfaces with soft slate borders. */
:root {
  --bg: #f5f7fb;
  --bg-elev: #ffffff;
  --bg-elev-2: #eef2f8;
  --border: #d7dde6;
  --text: #1c2541;
  --text-dim: #5a6a85;
  --primary: #1f4fb8;
  --primary-dark: #143a8c;
  --warning: #e87722;
  --warning-dark: #c45f12;
  --danger: #c0392b;
  --ok: #2e8e5e;
  --shadow: 0 4px 18px rgba(28, 37, 65, 0.08);
  /* Shared height anchors the sticky app-header, sidebar top offset, and table thead top. */
  --app-header-height: 60px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
}

/* ---------- Full-width app header (logo + brand + user avatar) ---------- */

.app-header {
  position: sticky;
  top: 0;
  z-index: 30;
  height: var(--app-header-height);
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 1.25rem;
  box-shadow: 0 1px 0 rgba(28, 37, 65, 0.03);
}

.app-header-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.app-header-logo {
  width: 36px;
  height: 36px;
  object-fit: contain;
}

.app-header-title {
  font-weight: 700;
  color: var(--primary);
  font-size: 1.4rem;
  letter-spacing: -0.01em;
}

/* ---------- App shell + sidebar (below the header) ---------- */

.app-shell {
  display: flex;
  align-items: stretch;
  min-height: calc(100vh - var(--app-header-height));
}

.main-area {
  flex: 1;
  min-width: 0;       /* lets the table-wrap horizontal scroll work inside the flex item */
  display: flex;
  flex-direction: column;
}

/* main below the section title bar fills the remaining vertical space so the
 * Applications embed iframe can stretch to fit. The Entities page's <main> has
 * its own padding/max-width applied later; this just gives it the flex slot. */
.main-area > main { flex: 1; min-height: 0; }

.section-title-bar {
  padding: 1rem 2rem;
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
}

.section-title-bar h1 {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--primary);
  letter-spacing: -0.005em;
}

.sidebar {
  width: 232px;
  flex-shrink: 0;
  background: var(--bg-elev);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: var(--app-header-height);
  height: calc(100vh - var(--app-header-height));
  transition: width 0.18s ease;
  z-index: 5;
}

.sidebar.collapsed { width: 68px; }

.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.75rem 0.55rem;
  flex: 1;
  overflow-y: auto;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.7rem;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  transition: background-color 0.1s ease;
}
.nav-item:hover { background: var(--bg-elev-2); }
.nav-item.active {
  background: rgba(31, 79, 184, 0.1);
  color: var(--primary);
}
.nav-item.active .nav-icon { color: var(--primary); }

.nav-icon {
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-dim);
}
.nav-icon svg { width: 100%; height: 100%; }

.sidebar.collapsed .nav-label { display: none; }
.sidebar.collapsed .nav-item  { justify-content: center; padding: 0.6rem; }

.sidebar-toggle {
  margin: 0.5rem;
  align-self: flex-end;
  width: 32px;
  height: 32px;
  border-radius: 6px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-dim);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.sidebar-toggle svg { width: 16px; height: 16px; transition: transform 0.18s ease; }
.sidebar-toggle:hover {
  background: var(--bg-elev-2);
  border-color: var(--border);
  color: var(--text);
}
.sidebar.collapsed .sidebar-toggle { align-self: center; }
.sidebar.collapsed .sidebar-toggle svg { transform: rotate(180deg); }

/* Application tile grid (Applications page) — one card per app. */
.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}

.app-tile {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 1rem 1.1rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 10px;
  text-decoration: none;
  color: var(--text);
  transition: border-color 0.12s ease, box-shadow 0.12s ease, transform 0.05s ease;
}
.app-tile:hover {
  border-color: var(--primary);
  box-shadow: var(--shadow);
}
.app-tile:active { transform: translateY(1px); }

.app-tile-icon {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background: rgba(31, 79, 184, 0.1);
  color: var(--primary);
}
.app-tile-icon svg { width: 22px; height: 22px; }

.app-tile-body {
  flex: 1;
  min-width: 0;
}

.app-tile-name {
  font-weight: 600;
  font-size: 0.98rem;
  color: var(--text);
}

.app-tile-host {
  font-size: 0.8rem;
  color: var(--text-dim);
  margin-top: 0.15rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.app-tile-arrow {
  color: var(--text-dim);
  font-size: 1rem;
  flex-shrink: 0;
}
.app-tile:hover .app-tile-arrow { color: var(--primary); }

/* ---------- Embedded app view (Applications → click a tile) ----------
 * The embed takes the full main slot: section-title bar is hidden via JS,
 * <main>'s padding is zeroed, the iframe fills 100%. A small floating circular
 * back button is overlaid in the top-left corner to return to the tile grid. */

main:has(.app-embed) { padding: 0; max-width: none; }

.app-embed {
  position: relative;            /* positioning context for the floating back button */
  display: flex;
  flex-direction: column;
  /* Flex:1 inherited from .main-area > main; the calc() is a defensive fallback
   * for browsers that don't propagate the flex height to <main>. */
  min-height: calc(100vh - var(--app-header-height));
  flex: 1;
  background: var(--bg);
}

.app-embed-frame {
  flex: 1;
  width: 100%;
  border: 0;
  background: #fff;
  min-height: calc(100vh - var(--app-header-height));
}

/* Floating back button — circular, brand-tinted, with a soft shadow so it
 * reads clearly on top of whatever the embedded app happens to render. */
.embed-back-btn {
  position: absolute;
  top: 0.85rem;
  left: 0.85rem;
  z-index: 5;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  box-shadow: 0 2px 8px rgba(28, 37, 65, 0.12);
  color: var(--text);
  text-decoration: none;
  transition: background-color 0.12s ease, color 0.12s ease, box-shadow 0.12s ease, transform 0.05s ease;
}
.embed-back-btn:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
  box-shadow: 0 3px 10px rgba(31, 79, 184, 0.3);
}
.embed-back-btn:active { transform: scale(0.96); }
.embed-back-btn svg { width: 18px; height: 18px; }

/* Modern avatar + dropdown account menu (replaces the old "Signed in as ..." line). */
.user-menu {
  position: relative;
  flex-shrink: 0;
}

button.user-avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
  color: #fff;
  font-weight: 600;
  font-size: 0.95rem;
  border: 1px solid rgba(255, 255, 255, 0.08);
  padding: 0;
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.05s ease;
}

button.user-avatar:hover:not(:disabled) {
  box-shadow: 0 0 0 3px rgba(31, 79, 184, 0.18);
  border-color: rgba(255, 255, 255, 0.18);
}

button.user-avatar:active:not(:disabled) {
  transform: scale(0.97);
}

button.user-avatar:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(31, 79, 184, 0.35);
}

.user-initials {
  line-height: 1;
  letter-spacing: 0.02em;
}

.user-dropdown {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: 240px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow);
  overflow: hidden;
  z-index: 20;
}

.user-dropdown-header {
  padding: 0.85rem 1rem 0.75rem;
}

.user-dropdown-name {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-dropdown-email {
  color: var(--text-dim);
  font-size: 0.82rem;
  margin-top: 0.15rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-dropdown-divider {
  height: 1px;
  background: var(--border);
}

.user-dropdown-item {
  display: block;
  padding: 0.65rem 1rem;
  color: var(--text);
  text-decoration: none;
  font-size: 0.9rem;
}

.user-dropdown-item:hover {
  background: var(--bg-elev-2);
}

main {
  /* Fit the main-area flex slot (which already accounts for the sidebar width)
   * and cap at 1800px on huge displays. Using % instead of vw is essential —
   * vw doesn't know about the sidebar and would overflow the main-area. */
  max-width: min(100%, 1800px);
  margin: 0;
  padding: 1.5rem 2rem 2rem;
}

.actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
}

button {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.35rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-elev);
  color: var(--text);
  cursor: pointer;
  text-align: left;
  font: inherit;
  transition: transform 0.05s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

button .label {
  font-weight: 600;
  font-size: 1.05rem;
}

button .hint {
  font-size: 0.8rem;
  color: var(--text-dim);
}

button:hover:not(:disabled) {
  border-color: var(--primary);
  box-shadow: var(--shadow);
}

button:active:not(:disabled) {
  transform: translateY(1px);
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

button.primary  { border-color: rgba(31, 79, 184, 0.35); }
button.warning  { border-color: rgba(232, 119, 34, 0.4); }
button.danger   { border-color: rgba(192, 57, 43, 0.4); }
button.primary:hover:not(:disabled)  { border-color: var(--primary); }
button.warning:hover:not(:disabled)  { border-color: var(--warning); }
button.danger:hover:not(:disabled)   { border-color: var(--danger); }

.status {
  padding: 1rem 1.25rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 6px;
  margin-bottom: 1.5rem;
}

.status p {
  margin: 0;
}

/* ---------- Inline progress strip (lives in the toolbar row between filter + buttons) ---------- */

.progress-inline {
  /* flex:1 so it fills the slack between toolbar-left (filter) and toolbar-right (CTAs).
   * min-width:0 lets the bar shrink with the toolbar instead of forcing a wrap on
   * tight viewports; the bar stays visible because flex-grow:1 always claims any
   * remaining space. */
  flex: 1;
  min-width: 0;
  max-width: 560px;
  margin: 0 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.82rem;
  align-self: center;
}

.progress-text {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  color: var(--text);
}

.progress-label    { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.progress-meta     { display: inline-flex; gap: 0.55rem; flex-shrink: 0; color: var(--text-dim); }
.progress-counter  { font-variant-numeric: tabular-nums; }
.progress-timer    { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 0.78rem; }

.progress-track {
  position: relative;
  height: 5px;
  border-radius: 3px;
  background: var(--bg-elev-2);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--primary);
  border-radius: 3px;
  width: 0%;
  transition: width 0.25s ease;
}

/* Indeterminate variant — bouncing partial fill while we wait for the first
 * poll cycle to report real stagesCompleted/Total numbers. */
.progress-fill.indeterminate {
  width: 35%;
  transition: none;
  animation: progress-indeterminate 1.4s ease-in-out infinite;
}

@keyframes progress-indeterminate {
  0%   { transform: translateX(-100%); }
  50%  { transform: translateX(180%); }
  100% { transform: translateX(-100%); }
}

/* ---------- Completion toast (bottom-right) ---------- */

.toast {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  padding: 0.7rem 1rem;
  border-radius: 8px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-left: 4px solid var(--primary);
  color: var(--text);
  font-size: 0.88rem;
  font-weight: 500;
  box-shadow: 0 4px 18px rgba(28, 37, 65, 0.16);
  z-index: 100;
  animation: toast-in 0.18s ease-out;
}
.toast-ok    { border-left-color: var(--ok); }
.toast-error { border-left-color: var(--danger); }

@keyframes toast-in {
  from { transform: translateY(8px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

.result {
  padding: 1.5rem 2rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.result h2 {
  margin: 0 0 1rem;
  font-size: 1.15rem;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.5rem;
}

#report h1 { font-size: 1.3rem; margin-top: 1.5rem; }
#report h2 { font-size: 1.15rem; margin-top: 1.5rem; border: 0; padding: 0; }
#report h3 { font-size: 1rem; margin-top: 1.25rem; color: var(--text); }

#report table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.75rem 0 1.5rem;
  font-size: 0.9rem;
}

#report th, #report td {
  text-align: left;
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

#report th {
  background: var(--bg-elev-2);
  font-weight: 600;
  color: var(--text);
}

#report tr:hover td { background: rgba(28, 37, 65, 0.03); }

#report code {
  background: var(--bg-elev-2);
  padding: 0.1rem 0.4rem;
  border-radius: 3px;
  font-size: 0.85em;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}

#report a { color: var(--primary); }

#report blockquote, #report em { color: var(--text-dim); }

.error {
  padding: 1.5rem;
  background: rgba(192, 57, 43, 0.08);
  border: 1px solid var(--danger);
  border-radius: 8px;
  margin-top: 1.5rem;
}

.error h2 {
  margin: 0 0 0.75rem;
  color: var(--danger);
}

.error pre {
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 0.85rem;
  color: var(--text-dim);
  margin: 0;
}

/* ---------- Phase B: hierarchy dashboard ---------- */

/* Toolbar stays on a single row even when the CTAs widen (e.g.
 * "Refresh N selected" / "Update N selected"). flex-shrink:0 on the
 * right group keeps the buttons inline; the left group is allowed to
 * shrink so the filter input absorbs any squeeze. */
.toolbar {
  display: flex;
  flex-wrap: nowrap;
  gap: 1rem;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: nowrap;     /* filter input + BRYTER toggle stay on the same row */
  min-width: 0;          /* lets the filter input shrink instead of forcing a wrap */
  flex-shrink: 1;
}

.toolbar-right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: nowrap;
  flex-shrink: 0;        /* keep all four CTAs on the same line as the filter */
}

.freshness-text {
  color: var(--text-dim);
  font-size: 0.85rem;
}

/* Toolbar CTA buttons — solid Ravago blue for the primary write action,
 * lighter blue tint for the secondary read action. */
button.cta {
  font-size: 0.88rem;
  font-weight: 600;
  padding: 0.45rem 0.95rem;
  border-radius: 6px;
  cursor: pointer;
  border: 1px solid transparent;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  line-height: 1;
  transition: background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}

button.cta-primary {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
button.cta-primary:hover:not(:disabled) {
  background: var(--primary-dark);
  border-color: var(--primary-dark);
}
button.cta-primary:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(31, 79, 184, 0.3);
}

button.cta-secondary {
  background: #d8e2f6;       /* soft tint of --primary */
  color: var(--primary-dark);
  border-color: #c2d1ee;
}
button.cta-secondary:hover:not(:disabled) {
  background: #c2d1ee;
  border-color: #aabfe4;
}
button.cta-secondary:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(31, 79, 184, 0.25);
}

/* Tertiary CTA: outlined-only, icon-only. Used for utility toolbar buttons
 * (Schedule, Columns) that share the row with the primary Refresh/Update
 * actions. Square shape sized to roughly match the labeled CTAs' overall
 * height so the toolbar reads as one consistent row of controls. */
button.cta-ghost {
  background: transparent;
  color: var(--text-dim);
  border-color: var(--border);
  /* Override .cta's wider padding for a compact square icon button. */
  padding: 0;
  width: 32px;
  height: 32px;
  justify-content: center;
}
button.cta-ghost:hover:not(:disabled) {
  background: var(--bg-elev-2);
  border-color: var(--primary);
  color: var(--primary);
}
button.cta-ghost:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(31, 79, 184, 0.2);
}
button.cta-ghost svg { width: 16px; height: 16px; display: block; }

button.cta:disabled { opacity: 0.55; cursor: not-allowed; }

.filter input {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 0.4rem 0.7rem;
  font: inherit;
  width: 240px;
  min-width: 0;
  max-width: 100%;       /* lets the input shrink when the toolbar tightens */
}

.filter input:focus { outline: none; border-color: var(--primary); }

/* "Show only BRYTER records" audit toggle. Sits inline with the filter
 * input in .toolbar-left. The count suffix appears only when the toggle is
 * off and the BRYTER-eligible subset differs from the full KLEA set.
 *
 * flex-shrink:0 + white-space:nowrap so the toggle never wraps or clips
 * its label — the filter input absorbs the squeeze instead. */
.bryter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
  flex-shrink: 0;
  white-space: nowrap;
}
.bryter-toggle input { margin: 0; cursor: pointer; }
.bryter-toggle-count {
  font-size: 0.78rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.meta-banner {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.85rem;
  color: var(--text-dim);
  margin-bottom: 1rem;
}

.meta-totals {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: center;
  flex: 1;
  min-width: 0;
}

.meta-banner .freshness-text {
  /* Pushed to the far right of the ribbon. flex-shrink:0 so long totals don't squeeze it out. */
  margin-left: auto;
  flex-shrink: 0;
  white-space: nowrap;
}

.meta-banner strong { color: var(--text); }
.meta-banner .dot   { color: var(--border); }

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
}

table.hierarchy {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
  /* fixed layout makes the <colgroup> widths authoritative — required for column resizing. */
  table-layout: fixed;
}

table.hierarchy th,
table.hierarchy td {
  text-align: left;
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  /* truncate long values with an ellipsis rather than wrapping (resize the column if you need more). */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

table.hierarchy thead th {
  background: var(--bg-elev-2);
  font-weight: 600;
  /* `position: relative` is needed so the absolutely-positioned .col-resizer handle
   * has the th as its positioning context. We intentionally do NOT use position:sticky
   * here — .table-wrap's `overflow-x: auto` makes it a scroll container for both
   * axes per spec, which would constrain the sticky thead in a way that breaks
   * the page-level vertical scroll experience. */
  position: relative;
  z-index: 1;
}

table.hierarchy .col-check     { padding-left: 0.6rem; padding-right: 0; text-align: center; }
table.hierarchy .col-check input { cursor: pointer; margin: 0; vertical-align: middle; }
table.hierarchy .col-name      { font-weight: 500; }
table.hierarchy .col-id        { font-family: ui-monospace, "SF Mono", Menlo, monospace; color: var(--text-dim); }
table.hierarchy .col-num       { text-align: right; font-variant-numeric: tabular-nums; }
table.hierarchy .col-status        { text-align: center; }
table.hierarchy .col-status-rollup { text-align: center; }

/* Pin the Actions column to the right of the horizontally-scrollable .table-wrap
 * so the per-row buttons remain visible regardless of scroll position. Grey tint
 * (var(--bg-elev-2)) keeps it visually distinct from the scrolling content.
 *
 * NB: we paint the left edge via box-shadow (not border-left). border-collapse:
 * collapse on the table makes cell borders unreliable when combined with
 * position: sticky — they vanish at scrollLeft=0 in WebKit/Blink because the
 * border is owned by the table grid, not the sticky cell. The inset shadow is
 * painted by the cell itself, so it's always visible. */
table.hierarchy th.col-actions,
table.hierarchy td.col-actions {
  text-align: center;
  position: sticky;
  right: 0;
  background: var(--bg-elev-2);
  box-shadow:
    inset 2px 0 0 0 #aab4c6,                      /* solid 2px left "border" */
    -6px 0 8px -6px rgba(28, 37, 65, 0.18);       /* soft drop shadow for separation */
  z-index: 1;
}
table.hierarchy thead th.col-actions {
  z-index: 3;  /* above sticky body cells (z:1) and sticky thead (z:1) */
}
/* Keep the pinned cell grey on row hover / expand so it doesn't lose its "pinned" look. */
tr.row-company:hover td.col-actions,
tr.row-company.expanded td.col-actions {
  background: var(--bg-elev-2);
}

/* Drag-to-resize handle that sits on the right edge of each th. */
.col-resizer {
  position: absolute;
  top: 0;
  right: 0;
  width: 6px;
  height: 100%;
  cursor: col-resize;
  user-select: none;
  z-index: 2;
}
.col-resizer:hover { background: var(--primary); opacity: 0.4; }
body.col-resizing { cursor: col-resize; user-select: none; }
body.col-resizing .col-resizer { background: var(--primary); opacity: 0.6; }

table.directors th.col-status,
table.directors td.col-status      { text-align: center; white-space: nowrap; padding-left: 1rem; padding-right: 1rem; }
/* Director-row Actions column: width-matched to the parent's 110px so its left
 * edge sits at the same x as the parent's pinned Actions column, with the same
 * grey tint + 2px slate left border + soft outer shadow for visual continuity.
 * Without an explicit width, the auto-layout sub-table would size this column
 * to its content (~80px) and the borders wouldn't line up. */
table.directors th.col-actions,
table.directors td.col-actions {
  width: 110px;
  min-width: 110px;
  text-align: center;
  white-space: nowrap;
  background: var(--bg-elev-2);
  box-shadow:
    inset 2px 0 0 0 #aab4c6,
    -6px 0 8px -6px rgba(28, 37, 65, 0.18);
}

.rollup-count {
  margin-left: 0.35rem;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.85em;
  color: var(--text-dim);
}

.validation-error {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.5rem;
  border-radius: 4px;
  background: rgba(232, 119, 34, 0.1);
  border: 1px solid rgba(232, 119, 34, 0.35);
  color: var(--warning);
  font-size: 0.78rem;
  font-weight: 500;
  cursor: help;
}

tr.row-company { cursor: pointer; }
tr.row-company:hover td { background: rgba(28, 37, 65, 0.03); }
tr.row-company.expanded td { background: rgba(31, 79, 184, 0.05); }

/* Non-BRYTER audit row. Muted text + faded background so users don't
 * read the empty BRYTER/CPAI columns as a sync failure. No expand cursor —
 * these rows have no directors detail row to open. */
tr.row-non-bryter { cursor: default; }
tr.row-non-bryter td {
  color: var(--text-dim);
  background: rgba(28, 37, 65, 0.015);
}
tr.row-non-bryter:hover td { background: rgba(28, 37, 65, 0.04); }
tr.row-non-bryter td.col-name { font-weight: 400; }   /* override .col-name's font-weight: 500 */

/* "Is BRYTER?" column values — green for TRUE so the rare anomaly
 * (FALSE-flagged company that's actually in BRYTER) reads as routine, not
 * alarming; gray for FALSE so it sits visually with the muted row. */
td.is-bryter-true  { color: var(--ok);       font-weight: 600; }
td.is-bryter-false { color: var(--text-dim); }

tr.row-detail .detail-cell {
  background: var(--bg);
  /* Left padding clears the L-shaped tree connector + lines the sub-table up
   * roughly with the Company name column above. Right padding is 0 so the
   * sub-table's right edge aligns flush with the parent table's right edge,
   * keeping the director-row Actions column border lined up with the parent's. */
  padding: 0.6rem 0 1rem 3.5rem;
  position: relative;          /* positioning context for the L connector */
  /* the parent rule sets nowrap+ellipsis on every td — undo it for the nested table's container. */
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

/* L-shaped tree connector visually anchors the directors sub-table to the
 * company row above it: a thin line drops out of the parent row and curves
 * right into the directors table. Pure CSS, no extra DOM. */
tr.row-detail .detail-cell::before {
  content: "";
  position: absolute;
  left: 1.65rem;
  top: 0;
  width: 1.1rem;
  height: 1.3rem;
  border-left:   2px solid #a4b1c4;
  border-bottom: 2px solid #a4b1c4;
  border-bottom-left-radius: 6px;
  pointer-events: none;
}

table.directors th,
table.directors td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;      /* fixed-layout columns truncate overflow cleanly */
}

/* Column widths for the directors sub-table live in the per-row <colgroup>
 * (see renderDirectorsRow in app.js). Fixed layout enforces them, with the
 * spacer column absorbing whatever horizontal slack is left so the Actions
 * column lines up with the parent table's pinned Actions border. The spacer
 * cells get no special treatment — they inherit the row bg + border-bottom
 * from the generic td rule, reading as an empty cell within the row. */

table.directors {
  /* Full-width so the Actions column can be pushed to the right via the
   * spacer column, lining up with the parent table's pinned Actions border.
   * NB: no right border — the parent table's Actions column has its own
   * left-edge inset shadow at the same x, and a 1px right border here would
   * push the directors' Actions cell 1px inward, visibly misaligning the
   * two vertical separators. */
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-size: 0.85rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-right: 0;
  border-radius: 4px 0 0 4px;
}

table.directors th,
table.directors td {
  padding: 0.45rem 0.6rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

table.directors thead th {
  background: var(--bg-elev-2);
  font-weight: 600;
  color: var(--text-dim);
}

table.directors tr:last-child td { border-bottom: 0; }

.status-icon {
  font-size: 1.05rem;
  line-height: 1;
  cursor: help;
}

.status-icon.ok       { color: var(--ok); }
.status-icon.missing  { color: var(--danger); }
.status-icon.partial  { color: var(--warning); }
.status-icon.pending  { color: var(--text-dim); }
.status-icon.warning  { color: var(--warning); }

.muted { color: var(--text-dim); font-size: 0.78rem; }

/* Per-row check (↻) + sync (↑) buttons.
 * Both icons share the brand blue so they read as the row-level analogs of
 * the global "Refresh all" / "Update all" CTAs in the toolbar. The .warning
 * class is kept for semantic grouping (sync is a write action) but uses the
 * same blue palette per design. */
button.row-btn {
  display: inline-block;
  flex-direction: row;
  padding: 0.15rem 0.4rem;
  margin: 0 0.1rem;
  font-size: 0.95rem;
  line-height: 1;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--primary);
  cursor: pointer;
  min-width: 0;
  text-align: center;
}
button.row-btn:hover:not(:disabled) {
  border-color: var(--primary);
  background: rgba(31, 79, 184, 0.1);
  color: var(--primary-dark);
}
button.row-btn.warning { color: var(--primary); }
button.row-btn.warning:hover:not(:disabled) {
  border-color: var(--primary);
  background: rgba(31, 79, 184, 0.1);
  color: var(--primary-dark);
}
button.row-btn:disabled { opacity: 0.5; cursor: wait; }
button.row-btn.error {
  border-color: var(--danger);
  color: var(--danger);
}

/* Per-row loading state: replaces the action buttons in the Actions cell
 * while a check/sync call is in flight. Stacked compact layout fits the
 * 110px cell width. */
.row-loading {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
  padding: 0.1rem 0.4rem;
}
.row-loading-label {
  font-size: 0.78rem;
  color: var(--primary);
  font-weight: 500;
  text-align: center;
}
.row-loading-bar {
  position: relative;
  height: 3px;
  border-radius: 2px;
  background: var(--bg-elev);
  overflow: hidden;
}
.row-loading-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 40%;
  background: var(--primary);
  border-radius: 2px;
  animation: progress-indeterminate 1.2s ease-in-out infinite;
}

.legend {
  text-align: center;
  margin-top: 1.5rem;
  font-size: 0.8rem;
  color: var(--text-dim);
}

/* ---------- Column-settings modal ----------
 * Modal pattern: full-viewport dimmed backdrop + centered panel.
 * Body gets `.modal-open` while open to prevent background scroll.
 * Save/Cancel semantics — see app.js openColsModal/closeColsModal. */

body.modal-open { overflow: hidden; }

/* :not([hidden]) is required: `display: flex` on a bare `.modal-overlay` rule
 * would override the user-agent `[hidden] { display: none }` (author rules win
 * at equal specificity), and the modal would never hide. */
.modal-overlay:not([hidden]) {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(28, 37, 65, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}

.modal {
  background: var(--bg-elev);
  border-radius: 10px;
  box-shadow: 0 24px 48px rgba(28, 37, 65, 0.25);
  width: min(720px, 100%);
  max-height: calc(100vh - 3rem);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1.25rem;
  border-bottom: 1px solid var(--border);
}
.modal-header h2 {
  margin: 0;
  font-size: 1.05rem;
  color: var(--text);
  font-weight: 600;
}
.modal-close {
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font-size: 1.1rem;
  cursor: pointer;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  line-height: 1;
}
.modal-close:hover { background: var(--bg-elev-2); color: var(--text); }

.modal-body {
  padding: 1rem 1.25rem;
  overflow-y: auto;
  flex: 1;
}

.modal-hint {
  margin: 0 0 0.85rem;
  font-size: 0.83rem;
  color: var(--text-dim);
}

.cols-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}
@media (max-width: 640px) {
  .cols-grid { grid-template-columns: 1fr; }
}

.cols-section h3 {
  margin: 0 0 0.5rem;
  font-size: 0.82rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}

.cols-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
}

.cols-list-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elev);
  cursor: grab;
  user-select: none;
}
.cols-list-item:last-child { border-bottom: 0; }
.cols-list-item:active     { cursor: grabbing; }
.cols-list-item.dragging   { opacity: 0.5; }

.cols-handle {
  color: var(--text-dim);
  font-size: 0.9rem;
  line-height: 1;
  letter-spacing: -0.15em;     /* tighter '⋮⋮' so it reads as a single grip */
  width: 14px;
  text-align: center;
  cursor: grab;
}

.cols-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  cursor: pointer;
  font-size: 0.88rem;
  color: var(--text);
}
.cols-toggle input[type=checkbox] {
  cursor: pointer;
  margin: 0;
}
.cols-label { line-height: 1.2; }

.modal-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.85rem 1.25rem;
  border-top: 1px solid var(--border);
  background: var(--bg-elev-2);
}
.modal-actions {
  display: flex;
  gap: 0.5rem;
}

/* Link-styled CTA — used for the modal's "Reset to defaults" action so it
 * reads as a tertiary control beside the primary Save / secondary Cancel. */
button.cta-link {
  background: transparent;
  border-color: transparent;
  color: var(--text-dim);
  padding: 0.45rem 0.5rem;
}
button.cta-link:hover:not(:disabled) {
  color: var(--primary);
  text-decoration: underline;
}

/* ---------- Schedule modal ----------
 * Reuses the generic .modal-overlay / .modal scaffolding. Only the
 * form-specific bits (enabled toggle, day-of-week chip group, status
 * footer) need bespoke rules. */

.sched-row {
  margin: 0 0 1rem;
  display: block;
}
.sched-row:last-of-type { margin-bottom: 0; }

.sched-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}
.sched-toggle input { margin: 0; cursor: pointer; }

.sched-days {
  border: 0;
  padding: 0;
  margin: 0 0 1rem;
}
.sched-days legend {
  font-size: 0.82rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin-bottom: 0.4rem;
  padding: 0;
}
.sched-days {
  display: block;
}
.sched-days > label {
  /* Each day renders as a pill: clicking the label toggles the hidden checkbox. */
  display: inline-block;
  margin: 0 0.35rem 0.35rem 0;
  cursor: pointer;
  user-select: none;
}
.sched-days > label input[type=checkbox] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.sched-days > label span {
  display: inline-block;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  font-size: 0.85rem;
  color: var(--text-dim);
  transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.sched-days > label:hover span {
  border-color: var(--primary);
  color: var(--primary);
}
.sched-days > label input:checked + span {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.sched-days > label input:focus-visible + span {
  box-shadow: 0 0 0 3px rgba(31, 79, 184, 0.25);
}

.sched-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.85rem;
}
.sched-grid label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.82rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.sched-grid input[type=time],
.sched-grid select {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text);
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-elev);
}
.sched-grid input[type=time]:focus,
.sched-grid select:focus {
  outline: none;
  border-color: var(--primary);
}

.sched-status {
  margin: 0;
  padding: 0.6rem 0.85rem;
  border-radius: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  font-size: 0.83rem;
  color: var(--text-dim);
  line-height: 1.4;
}

/* ---------- Login page ----------
 * Standalone /login.html (no sidebar / app shell). Centered card with the
 * brand + email/password form + secondary "Sign in with AAD" link. */

body.login-body {
  background: var(--bg);
  min-height: 100vh;
  margin: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.login-shell {
  width: 100%;
  display: flex;
  justify-content: center;
  padding: 5vh 1.5rem 2rem;
}

.login-card {
  width: 100%;
  max-width: 380px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.75rem;
  box-shadow: var(--shadow);
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}
.login-logo { width: 36px; height: 36px; object-fit: contain; }
.login-title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--primary);
  letter-spacing: -0.005em;
}

.login-heading {
  margin: 0 0 0.85rem;
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--text);
}

.login-form { display: flex; flex-direction: column; gap: 0.85rem; }
.login-field { display: flex; flex-direction: column; gap: 0.3rem; }
.login-field span {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.login-field input {
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 0.55rem 0.7rem;
  font: inherit;
  font-size: 0.95rem;
}
.login-field input:focus { outline: none; border-color: var(--primary); }

.login-error {
  color: var(--danger);
  background: rgba(192, 57, 43, 0.08);
  border: 1px solid rgba(192, 57, 43, 0.25);
  padding: 0.5rem 0.7rem;
  border-radius: 6px;
  font-size: 0.85rem;
}

.login-submit { width: 100%; justify-content: center; margin-top: 0.3rem; }

.login-divider {
  margin: 1.25rem 0 1rem;
  text-align: center;
  position: relative;
  color: var(--text-dim);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.login-divider::before,
.login-divider::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 40%;
  height: 1px;
  background: var(--border);
}
.login-divider::before { left: 0; }
.login-divider::after  { right: 0; }
.login-divider span { background: var(--bg-elev); padding: 0 0.6rem; position: relative; }

.login-aad { width: 100%; justify-content: center; text-decoration: none; }

/* ---------- Admin: Manage users ---------- */

.admin-main {
  padding: 1.5rem 2rem 2rem;
  max-width: 1200px;
  width: 100%;
}

.admin-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

.admin-hint {
  margin: 0;
  font-size: 0.88rem;
  color: var(--text-dim);
  flex: 1;
  min-width: 240px;
}
.admin-hint strong { color: var(--text); }

.admin-table-wrap {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.admin-table th,
.admin-table td {
  text-align: left;
  padding: 0.65rem 0.9rem;
  border-bottom: 1px solid var(--border);
}
.admin-table thead th {
  background: var(--bg-elev-2);
  font-weight: 600;
  color: var(--text-dim);
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.admin-table tbody tr:last-child td { border-bottom: 0; }

.admin-empty {
  text-align: center;
  color: var(--text-dim);
  padding: 1.5rem;
}

.admin-actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.admin-pill {
  display: inline-block;
  padding: 0.18rem 0.55rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.admin-pill-ok   { background: rgba(46, 142, 94, 0.12);  color: var(--ok); }
.admin-pill-warn { background: rgba(232, 119, 34, 0.12); color: var(--warning-dark); }

/* Compact CTA variant for table actions. */
button.cta-sm { padding: 0.32rem 0.7rem; font-size: 0.82rem; }

/* Danger CTA — used for destructive admin actions (Delete user). */
button.cta-danger {
  background: var(--bg-elev);
  color: var(--danger);
  border-color: rgba(192, 57, 43, 0.35);
}
button.cta-danger:hover:not(:disabled) {
  background: rgba(192, 57, 43, 0.08);
  border-color: var(--danger);
}

/* Login fineprint — used on /login.html, /change-password.html for the
 * "minimum 10 chars" hint under the form fields. */
.login-fineprint,
.login-hint {
  margin: 0;
  font-size: 0.8rem;
  color: var(--text-dim);
  line-height: 1.4;
}
.login-hint {
  padding: 0.6rem 0.8rem;
  background: rgba(232, 119, 34, 0.08);
  border: 1px solid rgba(232, 119, 34, 0.25);
  border-radius: 6px;
  margin-bottom: 0.85rem;
  color: var(--warning-dark);
  font-size: 0.85rem;
}

/* Temp-password modal: one-shot reveal with copy button. */
.temp-pw-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.4rem 0 0.6rem;
}
.temp-pw-value {
  flex: 1;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 1rem;
  padding: 0.55rem 0.7rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  user-select: all;
  word-break: break-all;
}
