
/* ========== design-tokens.css ========== */
/* Client portal design tokens — VS Code Dark+ palette.
   GENERATED from design/tokens/dark-plus.json by `npm run tokens:gen` (idea #1426).
   Do NOT hand-edit the values or the BEGIN/END GENERATED TOKENS block — change the
   source JSON and regenerate, or `npm run tokens:check` will flag the drift. */

/* =============================================
   DESIGN TOKENS
   ============================================= */
:root {
    /* BEGIN GENERATED TOKENS — source: design/tokens/dark-plus.json (npm run tokens:gen) */
    --bg-input: #3c3c3c;
    --accent-chrome: #007acc;
    --focus-ring: #007fd4;
    --selection-bg: #264f78;
    --link-color: #3794ff;
    --link-hover: #4daafc;
    --border-strong: #474747;
    --success-subtle: rgba(137, 209, 133, .16);
    --danger-subtle: rgba(241, 76, 76, .16);
    --warning-subtle: rgba(204, 167, 0, .16);
    --purple: #c586c0;
    --purple-subtle: rgba(197, 134, 192, .18);
    --teal: #4ec9b0;
    --teal-subtle: rgba(78, 201, 176, .18);
    --yellow-sc: #dcdcaa;
    --orange: #d18616;
    /* END GENERATED TOKENS */
    --bg-primary: #1e1e1e;
    --bg-secondary: #252526;
    --bg-tertiary: #2d2d30;
    --bg-elevated: #333333;
    --text-primary: #d4d4d4;
    --text-secondary: #9d9d9d;
    --text-muted: #808080;
    --accent-color: #3794ff;
    --accent-hover: #4daafc;
    --accent-subtle: rgba(55, 148, 255, .12);
    --border-color: #3c3c3c;
    --border-subtle: #2d2d30;
    --success: #89d185;
    --danger: #f14c4c;
    --warning: #cca700;
    --radius-sm: 6px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .25);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, .32);
    --shadow-lg: 0 8px 28px rgba(0, 0, 0, .42);
    --transition: 0.15s ease;
}



/* ========== reset-base.css ========== */
/* =============================================
   RESET & BASE
   ============================================= */
*, *::before, *::after { box-sizing: border-box; }

body.cns-dark-theme {
    margin: 0;
    padding: 0;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    font-size: 14px;
    line-height: 1.5;
    height: 100vh;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

::selection {
    background: var(--accent-color);
    color: white;
}

/* Scrollbar styling */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }



/* ========== buttons.css ========== */
/* =============================================
   BUTTONS
   ============================================= */
.cp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 16px;
    font-size: 0.85rem;
    font-weight: 500;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    cursor: pointer;
    transition: all var(--transition);
    text-decoration: none;
    line-height: 1.4;
    white-space: nowrap;
    background: transparent;
    color: var(--text-primary);
}
.cp-btn:focus { outline: none; box-shadow: 0 0 0 2px var(--accent-subtle); }
.cp-btn:active { transform: scale(0.97); }
.cp-btn:disabled,
.cp-btn.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* ── Solid variants ──────────────────────────── */
.cp-btn-primary {
    background: var(--accent-color);
    color: #fff;
    border-color: var(--accent-color);
}
.cp-btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

.cp-btn-secondary {
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border-color: var(--border-color);
}
.cp-btn-secondary:hover { background: var(--border-color); }

.cp-btn-success {
    background: var(--success);
    color: #fff;
    border-color: var(--success);
}
.cp-btn-success:hover { background: #2ea043; border-color: #2ea043; }

.cp-btn-danger {
    background: var(--danger);
    color: #fff;
    border-color: var(--danger);
}
.cp-btn-danger:hover { background: #da3633; border-color: #da3633; }

.cp-btn-warning {
    background: var(--warning);
    color: #1a1a1a;
    border-color: var(--warning);
}
.cp-btn-warning:hover { background: #b58217; border-color: #b58217; }

.cp-btn-info.active,
.cp-btn-info[aria-pressed="true"] {
    background: #0d4f9e;
    border-color: #0d4f9e;
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.35);
}
.cp-btn-info {
    background: #1f6feb;
    color: #fff;
    border-color: #1f6feb;
}
.cp-btn-info:hover { background: #388bfd; border-color: #388bfd; }

/* ── Outline variants ────────────────────────── */
.cp-btn-outline-primary {
    background: transparent;
    color: var(--accent-color);
    border-color: var(--accent-color);
}
.cp-btn-outline-primary:hover { background: var(--accent-subtle); color: var(--accent-hover); }

.cp-btn-outline-secondary {
    background: transparent;
    color: var(--text-secondary);
    border-color: var(--border-color);
}
.cp-btn-outline-secondary:hover { background: var(--bg-elevated); color: var(--text-primary); border-color: var(--text-muted); }

.cp-btn-outline-success {
    background: transparent;
    color: var(--success);
    border-color: var(--success);
}
.cp-btn-outline-success:hover { background: rgba(63,185,80,.15); }

.cp-btn-outline-danger {
    background: transparent;
    color: var(--danger);
    border-color: var(--danger);
}
.cp-btn-outline-danger:hover { background: rgba(248,81,73,.15); }

.cp-btn-outline-warning {
    background: transparent;
    color: var(--warning);
    border-color: var(--warning);
}
.cp-btn-outline-warning:hover { background: rgba(210,153,34,.15); }

.cp-btn-outline-info {
    background: transparent;
    color: #58a6ff;
    border-color: #1f6feb;
}
.cp-btn-outline-info:hover { background: rgba(31,111,235,.15); color: #79c0ff; }
/* Depressed/toggle state — used by the asset History button so an open
   timeline reads as "this view is on" instead of just looking idle. */
.cp-btn-outline-info.active,
.cp-btn-outline-info[aria-pressed="true"] {
    background: #1f6feb;
    color: #fff;
    border-color: #1f6feb;
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.35);
}

/* ── Link ─────────────────────────────────────── */
.cp-btn-link {
    background: transparent;
    color: var(--accent-color);
    border-color: transparent;
    padding: 4px 6px;
    text-decoration: none;
}
.cp-btn-link:hover { color: var(--accent-hover); text-decoration: underline; }

/* ── Sizes ────────────────────────────────────── */
.cp-btn-sm { padding: 4px 10px; font-size: 0.8rem; }
.cp-btn-lg { padding: 10px 20px; font-size: 0.95rem; }


/* ========== badges.css ========== */
/* =============================================
   BADGES
   ============================================= */
.cp-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 7px;
    font-size: 0.65rem;
    font-weight: 600;
    border-radius: 10px;
    line-height: 1.4;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
.cp-badge.cp-badge-muted {
    background: var(--bg-tertiary) !important;
    color: var(--text-secondary);
    border: 1px solid var(--border-color);
}

/* =============================================
   ASSET-LINK PILLS
   .linked-asset-link is used in two distinct shapes in views/assets.js:
     • inline anchor inside a row/cell, originally `text-info` (cyan) —
       hard to read against the dark theme. These get the pill treatment.
     • full-row card / list-group-item / flex-row variants — those never
       carry `text-info`, so the .cp-text-info compound selector below leaves
       them alone.
   ============================================= */
a.linked-asset-link.cp-text-info,
a.cp-text-info.linked-asset-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 9px;
    font-size: 0.78rem;
    font-weight: 500;
    line-height: 1.5;
    text-decoration: none;
    color: var(--text-primary) !important;
    /* Tint is brighter than --bg-tertiary so the pill remains visible against
       any of the dark surfaces in use (bg-secondary / elevated cards /
       inline table cells). Still muted enough that a row of pills doesn't
       read as a row of buttons. */
    background: rgba(255, 255, 255, 0.07);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 999px;
    transition: background var(--transition), border-color var(--transition);
    /* Keep inline FontAwesome icons aligned and toned down to the muted
       palette so the pill doesn't read as a bright callout. */
}
a.linked-asset-link.cp-text-info > .fa-solid,
a.linked-asset-link.cp-text-info > .fa-regular,
a.linked-asset-link.cp-text-info > .fa-brands,
a.cp-text-info.linked-asset-link > .fa-solid,
a.cp-text-info.linked-asset-link > .fa-regular,
a.cp-text-info.linked-asset-link > .fa-brands {
    color: var(--text-secondary);
    font-size: 0.72rem;
}
a.linked-asset-link.cp-text-info:hover,
a.cp-text-info.linked-asset-link:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: var(--accent-color);
    color: var(--text-primary) !important;
}



/* ========== form-controls.css ========== */
/* =============================================
   FORM CONTROLS
   ============================================= */
.cp-input {
    width: 100%;
    padding: 8px 12px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
    transition: border-color var(--transition);
    outline: none;
}
.cp-input:focus {
    border-color: var(--accent-color);
    box-shadow: 0 0 0 3px var(--accent-subtle);
}

.cp-check-input {
    width: 32px;
    height: 18px;
    appearance: none;
    -webkit-appearance: none;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 9px;
    cursor: pointer;
    position: relative;
    transition: all var(--transition);
    vertical-align: middle;
}
.cp-check-input::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 12px;
    height: 12px;
    background: var(--text-muted);
    border-radius: 50%;
    transition: all var(--transition);
}
.cp-check-input:checked {
    background: var(--accent-color);
    border-color: var(--accent-color);
}
.cp-check-input:checked::after {
    left: 16px;
    background: #fff;
}
.cp-check { display: flex; align-items: center; gap: 8px; }
.cp-check-label { color: var(--text-secondary); font-size: 0.8rem; cursor: pointer; user-select: none; }



/* ========== cards.css ========== */
/* =============================================
   CARDS & LIST GROUPS
   ============================================= */
.cp-card {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    color: var(--text-primary);
}

.cp-card-header {
    background-color: var(--bg-tertiary);
    border-bottom: 1px solid var(--border-color);
    border-radius: calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px) 0 0 !important;
}

.cp-card-body {
    padding: 1rem;
    flex: 1 1 auto;
}

.list-group-item {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
    transition: all var(--transition);
}

.list-group-item:hover, .list-group-item:focus {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
}

.list-group-item.active {
    background-color: var(--accent-subtle) !important;
    border-color: var(--accent-color) !important;
    color: var(--accent-color) !important;
}



/* ========== empty-state.css ========== */
/* =============================================
   EMPTY STATE
   ============================================= */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    text-align: center;
    color: var(--text-muted);
    padding: 40px;
}
.empty-state i {
    font-size: 3.5rem;
    margin-bottom: 16px;
    opacity: 0.3;
}
.empty-state p {
    font-size: 1rem;
    margin: 0 0 16px 0;
}
.empty-text {
    color: var(--text-muted);
    font-size: 0.85rem;
    padding: 20px 14px;
    text-align: center;
}

.loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 30px;
    color: var(--text-muted);
    font-size: 0.9rem;
    gap: 8px;
}



/* ========== confirm-modal.css ========== */
/* /docs/public/css/modules/confirm-modal.css
   Native-dialog replacement; see js/modules/confirmModal.js. Mirrors
   the chrome extension's ConfirmationModal shape (header + X / round
   icon body / right-aligned footer), themed with docs design tokens. */

.cm-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10050;
    opacity: 0;
    transition: opacity 0.18s ease;
}

.cm-backdrop.show {
    opacity: 1;
}

.cm-dialog {
    background: var(--bg-elevated, #1c2129);
    color: var(--text-primary, #e6edf3);
    border: 1px solid var(--border-color, #30363d);
    border-radius: var(--radius-lg, 12px);
    box-shadow: var(--shadow-lg, 0 8px 24px rgba(0,0,0,.5));
    width: 400px;
    max-width: 90vw;
    transform: scale(0.94);
    transition: transform 0.18s ease;
}

.cm-backdrop.show .cm-dialog {
    transform: scale(1);
}

.cm-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border-subtle, #21262d);
}

.cm-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary, #e6edf3);
}

.cm-close {
    background: none;
    border: none;
    color: var(--text-secondary, #8b949e);
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--radius-sm, 6px);
    font-size: 14px;
    transition: background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
}

.cm-close:hover {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-primary, #e6edf3);
}

.cm-body {
    padding: 22px 20px;
    text-align: center;
}

.cm-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 14px;
    font-size: 24px;
}

/* Type-tinted icon background + colour. Buttons inherit the same hue. */
.cm-type-danger  .cm-icon { background: rgba(248, 81, 73, 0.18);  color: var(--danger,  #f85149); }
.cm-type-warning .cm-icon { background: rgba(210, 153, 34, 0.22); color: var(--warning, #d29922); }
.cm-type-info    .cm-icon { background: rgba(88, 166, 255, 0.18); color: var(--accent-color, #58a6ff); }
.cm-type-success .cm-icon { background: rgba(63, 185, 80, 0.18);  color: var(--success, #3fb950); }

.cm-message {
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-primary, #e6edf3);
}

.cm-input {
    margin-top: 14px;
    width: 100%;
    padding: 10px 12px;
    background: var(--bg-secondary, #161b22);
    border: 1px solid var(--border-color, #30363d);
    border-radius: var(--radius-sm, 6px);
    color: var(--text-primary, #e6edf3);
    font-size: 14px;
    outline: none;
    transition: border-color var(--transition, 0.15s ease);
}

.cm-input:focus {
    border-color: var(--accent-color, #58a6ff);
}

.cm-footer {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 14px 18px;
    border-top: 1px solid var(--border-subtle, #21262d);
}

.cm-btn {
    padding: 8px 16px;
    border: none;
    border-radius: var(--radius-sm, 6px);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: filter var(--transition, 0.15s ease), background var(--transition, 0.15s ease);
}

.cm-btn-secondary {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-primary, #e6edf3);
}

.cm-btn-secondary:hover {
    background: rgba(255, 255, 255, 0.14);
}

.cm-btn-primary {
    color: #fff;
    background: var(--accent-color, #58a6ff);
}

.cm-type-danger  .cm-btn-primary { background: var(--danger,  #f85149); }
.cm-type-warning .cm-btn-primary { background: var(--warning, #d29922); color: #1a1a1a; }
.cm-type-success .cm-btn-primary { background: var(--success, #3fb950); color: #1a1a1a; }
.cm-type-info    .cm-btn-primary { background: var(--accent-color, #58a6ff); }

.cm-btn-primary:hover {
    filter: brightness(1.12);
}


/* ========== portal.css ========== */
/* portal.css — client portal layout + components, built on the docs design
   tokens (design-tokens.css) for visual consistency with the docs site. */

html, body {
  height: 100%;
}

body.cns-dark-theme {
  margin: 0;
  background: var(--bg-primary);
  color: var(--text-primary);
  font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* --- App chassis (topbar + nav + shell) ------------------------------------ */

.portal-app {
  display: flex;
  flex-direction: column;
  height: 100%;
  box-sizing: border-box;
}

/* Top bar — slim, sticky identity strip. */
.portal-topbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-color);
}

.topbar-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 0.95rem;
}

.topbar-brand i { color: var(--accent-color); }

.topbar-identity {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.topbar-id-text {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.2;
  min-width: 0;
}

.topbar-company { font-size: 0.82rem; font-weight: 600; color: var(--text-primary); }
.topbar-user { font-size: 0.72rem; color: var(--text-secondary); }

.topbar-status-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--text-muted);
}

.topbar-status-dot.status-success { background: var(--success); }
.topbar-status-dot.status-warning { background: var(--warning); }
.topbar-status-dot.status-danger  { background: var(--danger); }
.topbar-status-dot.status-neutral { background: var(--text-muted); }

/* Topbar icon buttons — refresh (reloadPortalWithAuth) + open-external. */
.topbar-refresh,
.topbar-external {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-left: 4px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  cursor: pointer;
  transition: var(--transition);
}
.topbar-refresh:hover,
.topbar-external:hover { color: var(--accent-color); border-color: var(--accent-color); }
.topbar-refresh:active,
.topbar-external:active { transform: scale(0.96); }
/* Sign-out button (idea #1078) — same chrome as the other topbar buttons, danger accent. */
.topbar-logout {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-left: 4px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  cursor: pointer;
  transition: var(--transition);
}
.topbar-logout:hover { color: var(--danger); border-color: var(--danger); }
.topbar-logout:active { transform: scale(0.96); }
.topbar-logout.is-hidden { display: none; }

/* The open-in-browser button only makes sense inside the mobile-sized native
   tray — hidden on desktop, shown at the mobile breakpoint. */
.topbar-external { display: none; }
@media (max-width: 768px) {
  .topbar-external { display: inline-flex; }
}

/* Section nav — icon + label tabs. */
.portal-nav {
  flex-shrink: 0;
  display: flex;
  gap: 4px;
  padding: 6px 12px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-color);
  overflow-x: auto;
  scrollbar-width: none;
}

.portal-nav::-webkit-scrollbar { display: none; }

.nav-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.82rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.nav-item i { font-size: 0.9rem; }

.nav-item:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}

.nav-item.is-active {
  background: var(--accent-subtle);
  color: var(--accent-color);
  border-color: var(--accent-color);
}

/* --- Shell ----------------------------------------------------------------- */

.portal-shell {
  /* Fluid by default — fills whatever container hosts the portal (tab, iframe,
     popup). Set --portal-max-width on .portal-shell to re-cap/centre it. */
  width: 100%;
  max-width: var(--portal-max-width, none);
  margin: 0 auto;
  padding: 16px;
  /* Flex child of .portal-app — takes the remaining height and becomes the
     scroll container. min-height:0 lets it actually shrink to fit the flex box
     (without it a tall child would push past the viewport, unscrollable). */
  flex: 1 1 auto;
  min-height: 0;
  box-sizing: border-box;
  overflow-y: auto;
  /* Styled thin scrollbar — Firefox; WebKit/Blink rules below. */
  scrollbar-width: thin;
  scrollbar-color: var(--border-color) transparent;
}

.portal-shell::-webkit-scrollbar { width: 8px; }
.portal-shell::-webkit-scrollbar-track { background: transparent; }
.portal-shell::-webkit-scrollbar-thumb {
  background: var(--border-color);
  border-radius: var(--radius-sm);
}
.portal-shell::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

.is-hidden {
  display: none !important;
}

.portal-view {
  animation: portal-fade 0.15s ease;
}

@keyframes portal-fade {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* --- Headings / sections --------------------------------------------------- */

.portal-heading {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 1rem;
  font-weight: 600;
  margin: 0 0 12px;
}

.portal-heading i {
  color: var(--accent-color);
}

.portal-heading.is-center {
  justify-content: center;
}

.section-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  margin: 16px 0 8px;
}

.back-btn {
  margin-bottom: 12px;
}

.portal-muted {
  color: var(--text-secondary);
  font-size: 0.85rem;
}

/* --- Welcome user meta ----------------------------------------------------- */

.welcome-banner {
  text-align: center;
  padding: 18px 16px;
  margin-bottom: 12px;
}

.welcome-banner .welcome-icon {
  font-size: 1.8rem;
  color: var(--accent-color);
  margin-bottom: 6px;
}

/* "Identified from your active session" indicator under the welcome greeting. */
.welcome-identified {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 8px auto 0;
  padding: 3px 10px;
  border-radius: 11px;
  font-size: 0.72rem;
  font-weight: 600;
}

.welcome-identified.status-success { background: var(--success-subtle); color: var(--success); }
.welcome-identified.status-info    { background: var(--accent-subtle); color: var(--accent-color); }
.welcome-identified.status-warning { background: var(--warning-subtle); color: var(--warning); }

.user-meta {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
  text-align: left;
  margin-top: 12px;
}

.user-meta .meta-label {
  display: block;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.user-meta .meta-value {
  font-size: 0.85rem;
  color: var(--text-primary);
}

/* --- Action cards ---------------------------------------------------------- */

.action-card {
  display: block;
  width: 100%;
  text-align: center;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: 18px 16px;
  margin-bottom: 10px;
  cursor: pointer;
  color: inherit;
  transition: background var(--transition), border-color var(--transition), transform var(--transition);
}

.action-card:hover {
  background: var(--bg-tertiary);
  border-color: var(--accent-color);
}

.action-card:active {
  transform: scale(0.99);
}

.action-card.is-busy {
  pointer-events: none;
  opacity: 0.75;
}

.action-card-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.action-card-icon {
  font-size: 1.5rem;
  color: var(--accent-color);
  margin-bottom: 4px;
}

.action-card-title {
  font-weight: 600;
}

.action-card-text {
  font-size: 0.8rem;
  color: var(--text-secondary);
}

/* Caption under the privileged (New User / Suspend) actions explaining why
   they're shown. */
.priv-note {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  font-size: 0.72rem;
  color: var(--text-muted);
}

.priv-note i {
  color: var(--accent-color);
}

/* Inline info callout (e.g. the alternate-contact guidance on the ticket form). */
.portal-note {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 14px;
  padding: 10px 12px;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--text-secondary);
  background: var(--accent-subtle);
  border: 1px solid var(--border-color);
  border-left: 3px solid var(--accent-color);
  border-radius: var(--radius-md);
}

.portal-note i {
  color: var(--accent-color);
  margin-top: 2px;
}

.portal-note strong {
  color: var(--text-primary);
}

/* --- Status pills (station-modal pattern: tinted bg + solid text) ---------- */

.status-pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 11px;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.status-success { background: var(--success-subtle); color: var(--success); }
.status-danger  { background: var(--danger-subtle); color: var(--danger); }
.status-warning { background: var(--warning-subtle); color: var(--warning); }
.status-info    { background: var(--accent-subtle); color: var(--accent-color); }
.status-neutral { background: rgba(139, 148, 158, 0.15); color: var(--text-secondary); }

/* --- Ticket list ----------------------------------------------------------- */

/* Filter + search toolbar above the ticket list. */
.ticket-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

.filter-tabs { display: inline-flex; gap: 4px; }

.filter-tab {
  padding: 5px 12px;
  border: 1px solid var(--border-color);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  border-radius: var(--radius-sm);
  font-size: 0.78rem;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.filter-tab:hover { background: var(--bg-tertiary); color: var(--text-primary); }

.filter-tab.is-active {
  background: var(--accent-subtle);
  color: var(--accent-color);
  border-color: var(--accent-color);
}

.ticket-search {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  flex: 1 1 160px;
  max-width: 260px;
}

.ticket-search i { color: var(--text-muted); font-size: 0.8rem; }

.ticket-search input {
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-size: 0.82rem;
  width: 100%;
  outline: none;
}

.ticket-search input::placeholder { color: var(--text-muted); }

/* Inline (within-list) empty state when a filter/search matches nothing. */
.empty-state.is-inline { padding: 20px 12px; }

.ticket-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ticket-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-left: 2px solid transparent;
  border-radius: var(--radius-md);
  padding: 10px 12px;
  color: inherit;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}

.ticket-row:hover {
  background: var(--bg-tertiary);
  border-left-color: var(--accent-color);
}

.ticket-row-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.ticket-row-title {
  font-size: 0.85rem;
  font-weight: 600;
}

.ticket-row-meta {
  font-size: 0.72rem;
  color: var(--text-muted);
}

/* --- Ticket details -------------------------------------------------------- */

.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 10px;
  margin: 12px 0;
}

.detail-item .detail-label {
  display: block;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.detail-item .detail-value {
  font-size: 0.85rem;
  color: var(--text-primary);
}

.activity-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.activity-item {
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-left: 2px solid var(--accent-color);
  border-radius: var(--radius-md);
  padding: 10px 12px;
}

/* The signed-in client's own message (their portal reply). */
.activity-item.is-mine { border-left-color: var(--success); }

/* A just-arrived action (live poll): slide in + a brief highlight ring. */
@keyframes activity-in {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}
@keyframes activity-flash {
  0% { box-shadow: 0 0 0 2px var(--success); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.activity-item.is-new { animation: activity-in 0.35s ease, activity-flash 1.8s ease; }

.activity-new-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 10px;
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--success-subtle);
  color: var(--success);
}

.activity-head {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.activity-title {
  font-size: 0.8rem;
  font-weight: 600;
}

.activity-date {
  font-size: 0.72rem;
  color: var(--text-muted);
}

.activity-body {
  font-size: 0.82rem;
  color: var(--text-secondary);
}

.activity-who {
  margin-top: 4px;
  font-size: 0.72rem;
  color: var(--text-muted);
}

/* --- Users directory ------------------------------------------------------- */

.users-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}

.users-toolbar .ticket-search { flex: 1 1 auto; max-width: none; }

/* Directory filter/search bar — pinned while the user list scrolls under it
   (#1987). The scroll container is .portal-shell (see the App chassis block),
   so this sticks to the top of the shell's scrollport; no nested scrollbar.
   The background must stay OPAQUE or the .user-card rows show through. */
.directory-toolbar {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--bg-primary);
  padding: 8px 0;
  margin-bottom: 8px;
}

.user-directory {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.user-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-left: 2px solid transparent;
  border-radius: var(--radius-md);
  padding: 12px;
}

.user-card.is-disabled { opacity: 0.7; border-left-color: var(--danger); }

.user-avatar {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent-subtle);
  color: var(--accent-color);
  font-size: 0.8rem;
  font-weight: 700;
}

.user-main { min-width: 0; flex: 1 1 auto; }

.user-name-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.user-name { font-size: 0.9rem; font-weight: 600; }

.user-badges { display: inline-flex; gap: 4px; flex-wrap: wrap; }

.user-sub {
  font-size: 0.78rem;
  color: var(--text-secondary);
  margin-top: 2px;
}

.user-contacts {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin-top: 6px;
}

.user-contact {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.78rem;
  color: var(--text-secondary);
  text-decoration: none;
}

a.user-contact:hover { color: var(--accent-color); }

.user-contact i { color: var(--text-muted); font-size: 0.75rem; }

/* --- Billing --------------------------------------------------------------- */

.billing-tabs { margin-bottom: 12px; }

.invoice-list,
.payment-list { display: flex; flex-direction: column; gap: 8px; }

.invoice-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-left: 2px solid transparent;
  border-radius: var(--radius-md);
  padding: 10px 12px;
  color: inherit;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}

.invoice-row:hover { background: var(--bg-tertiary); border-left-color: var(--accent-color); }
.invoice-row.is-overdue { border-left-color: var(--danger); }

.invoice-row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.invoice-row-title { font-size: 0.9rem; font-weight: 600; }
.invoice-row-meta { font-size: 0.72rem; color: var(--text-muted); }

.invoice-row-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.invoice-amount { font-size: 0.9rem; font-weight: 600; }

/* Invoice / payment tables. */
.billing-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
  margin-bottom: 8px;
}

.billing-table thead th {
  text-align: left;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  background: var(--bg-tertiary);
  padding: 7px 10px;
  border-bottom: 1px solid var(--border-color);
}

.billing-table tbody td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-primary);
}

.billing-table .num { text-align: right; white-space: nowrap; }

/* --- Forms ----------------------------------------------------------------- */

.portal-field {
  margin-bottom: 12px;
}

.portal-field label {
  display: block;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

.portal-field .req {
  color: var(--danger);
}

.portal-field .field-error {
  display: block;
  margin-top: 4px;
  font-size: 0.72rem;
  color: var(--danger);
}

.cp-input.has-error {
  border-color: var(--danger);
}

.cp-input.has-error:focus {
  box-shadow: 0 0 0 3px var(--danger-subtle);
}

.form-actions {
  margin-top: 16px;
}

.cp-btn-block {
  width: 100%;
  justify-content: center;
}

/* Ticket reply composer (under the history thread on the detail view). */
.reply-form { margin-top: 8px; }

/* Embedded onboarding form (single static page at /newuser, iframed in). */
.portal-embed {
  width: 100%;
  min-height: 70vh;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}

/* --- Toolbar / detail header ----------------------------------------------- */

.detail-toolbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.detail-toolbar-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

/* --- Toasts ---------------------------------------------------------------- */

.toast-stack {
  position: fixed;
  right: 16px;
  bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 1100;
}

.portal-toast {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 240px;
  max-width: 360px;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  border: 1px solid var(--border-color);
  border-left: 3px solid var(--accent-color);
  box-shadow: var(--shadow-lg);
  color: var(--text-primary);
  font-size: 0.85rem;
  cursor: pointer;
  opacity: 0;
  transform: translateX(12px);
  transition: opacity var(--transition), transform var(--transition);
}

.portal-toast.show {
  opacity: 1;
  transform: none;
}

.portal-toast i {
  font-size: 1rem;
}

.portal-toast-success { border-left-color: var(--success); }
.portal-toast-success i { color: var(--success); }
.portal-toast-danger, .portal-toast-error { border-left-color: var(--danger); }
.portal-toast-danger i, .portal-toast-error i { color: var(--danger); }
.portal-toast-warning { border-left-color: var(--warning); }
.portal-toast-warning i { color: var(--warning); }
.portal-toast-info i { color: var(--accent-color); }

/* --- Small utilities ------------------------------------------------------- */

.cp-text-success { color: var(--success) !important; }
.cp-text-warning { color: var(--warning) !important; }
.cp-text-danger { color: var(--danger) !important; }
.cp-mt-2 { margin-top: 8px; }
.cp-mb-2 { margin-bottom: 8px; }
.cp-ms-2 { margin-left: 8px; }

@media (max-width: 768px) {
  .portal-shell { padding: 12px; }
  .portal-topbar { padding: 8px 12px; }
  /* Icon-only brand to save width on phones. */
  .topbar-brand span { display: none; }
  .nav-item { padding: 7px 12px; }
  .nav-item span { font-size: 0.78rem; }
  /* Stack the invoice detail header + its actions. */
  .detail-toolbar { flex-direction: column; align-items: stretch; }
  .detail-toolbar-actions { flex-wrap: wrap; }
  /* Tighter billing tables + stacked user contact rows. */
  .billing-table { font-size: 0.78rem; }
  .billing-table thead th,
  .billing-table tbody td { padding: 6px 7px; }
  .user-contacts { flex-direction: column; gap: 4px; }
}

/* --- Users directory enrichments + suspend picker (idea #973) ------------- */

/* Pending-suspension highlight on a directory row. */
.user-card.is-pending { border-left: 3px solid var(--warning); background: var(--warning-subtle); }

/* Live linked-account chips. */
.user-accounts { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.acct-chip {
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
  padding: 1px 7px; border-radius: 10px;
  background: var(--accent-subtle); color: var(--accent-color); border: 1px solid var(--border-color);
}
.acct-chip.is-off { background: transparent; color: var(--text-muted); text-decoration: line-through; }

/* Last login / modified meta line. */
.user-meta-line { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 5px; font-size: 11.5px; color: var(--text-muted); }
.user-meta-line i { margin-right: 3px; }

/* Per-row Disable action. */
.user-actions { display: flex; align-items: center; margin-left: auto; padding-left: 8px; }

/* Suspend user searchable dropdown. */
.su-combo { position: relative; }
.su-results {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  max-height: 280px; overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--border-color);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
}
.su-result {
  display: flex; flex-direction: column; gap: 1px; width: 100%; text-align: left;
  padding: 8px 12px; background: none; border: 0; border-bottom: 1px solid var(--border-subtle); cursor: pointer;
}
.su-result:last-child { border-bottom: 0; }
.su-result:hover { background: var(--bg-tertiary); }
.su-result.is-empty { color: var(--text-muted); cursor: default; }
.su-result-name { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.su-result-sub { font-size: 11.5px; color: var(--text-secondary); }

/* Per-account suspend checkboxes + retention note. */
.su-accounts-list { display: flex; flex-direction: column; gap: 6px; }
.su-acct-row { display: flex; align-items: center; gap: 8px; }
.su-acct-off { color: var(--text-muted); font-size: 11px; }
.su-retain-note {
  display: flex; gap: 8px; align-items: flex-start; margin: 10px 0;
  font-size: 12.5px; line-height: 1.45; color: var(--text-secondary);
  background: var(--warning-subtle); border: 1px solid var(--border-color); border-radius: var(--radius-sm);
  padding: 10px 12px;
}
.su-retain-note i { color: var(--warning); margin-top: 2px; }


/* ========== chat.css ========== */
/* chat.css — native websocket chat (idea #1184). Bubble style ported from
   bundles/messages/css/messages.css, re-mapped to the portal design tokens.
   Direction drives everything via a single .message-bubble side class + :has(). */

/* Live ticket banner — appears when a tech attaches the chat to a ticket. */
.chat-ticket-banner {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
  background: var(--accent-subtle);
  border: 1px solid var(--accent-color);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-size: 0.85rem;
}
.chat-ticket-banner i { color: var(--accent-color); }
.chat-ticket-banner.is-hidden { display: none; }

/* Panel: message scroll area + input pinned below, filling the view height. The height below is
   a FALLBACK for browsers without :has(); when the chat view is active the rules further down
   flex it to the exact available height so the .chat-messages area is the only thing that scrolls. */
.chat-panel {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 220px);
  min-height: 320px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

/* Keep the whole chat on ONE page: when the chat view is the active one, the shell stops
   scrolling and the view + panel flex to fill exactly the viewport height, so the messages list
   scrolls internally rather than pushing the input off the page (idea #1184). A little extra
   bottom padding gives the input breathing room so it never sits flush against the page edge. */
main.portal-shell:has(> #view-chat:not(.is-hidden)) {
  overflow: hidden;
  padding-bottom: 24px;
}
main.portal-shell:has(> #view-chat:not(.is-hidden)) > #view-chat {
  display: flex;
  flex-direction: column;
  height: 100%;
}
main.portal-shell:has(> #view-chat:not(.is-hidden)) .chat-panel {
  height: auto;
  flex: 1 1 auto;
  min-height: 0;
}
.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
}

/* --- bubbles (ported) --- */
.message-wrapper {
  margin-bottom: 0.25rem;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 100%;
}
.message-wrapper:has(.message-bubble.inbound) { align-items: flex-start; }
.message-wrapper:has(.message-bubble.outbound) { align-items: flex-end; }

.message-container {
  display: flex;
  align-items: flex-start;
  max-width: 78%;
  margin-bottom: 0.125rem;
}
.message-wrapper:has(.message-bubble.inbound) .message-container { flex-direction: row; }
.message-wrapper:has(.message-bubble.outbound) .message-container { flex-direction: row-reverse; }

.user-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 600;
  font-size: 12px;
  flex-shrink: 0;
  text-transform: uppercase;
}
.message-wrapper:has(.message-bubble.inbound) .user-avatar { margin-right: 0.6rem; }
.message-wrapper:has(.message-bubble.outbound) .user-avatar { margin-left: 0.6rem; }
.user-avatar.outbound { background: var(--accent-color); }
.user-avatar.inbound { background: var(--bg-tertiary); color: var(--text-secondary); }

.message-content { min-width: 0; }
.user-info {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.125rem;
  flex-wrap: wrap;
}
.message-wrapper:has(.message-bubble.outbound) .user-info { flex-direction: row-reverse; }
.sender-name { font-weight: 600; color: var(--text-primary); font-size: 0.78rem; }
.message-timestamp { color: var(--text-muted); font-size: 0.7rem; }

.message-bubble {
  color: var(--text-primary);
  background: var(--bg-tertiary);
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-lg);
  word-wrap: break-word;
  overflow-wrap: anywhere;
  font-size: 0.9rem;
  line-height: 1.4;
  max-width: 100%;
}
.message-bubble.inbound { border-top-left-radius: 4px; }
.message-bubble.outbound {
  background: var(--accent-color);
  color: #0d1117;
  border-top-right-radius: 4px;
}
.message-text { white-space: pre-wrap; }

/* subtle entry animation for live messages */
.message-wrapper.is-new { animation: chatMsgIn 0.16s ease; }
@keyframes chatMsgIn {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* --- typing indicator --- */
.chat-typing {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.85rem 0.4rem;
  color: var(--text-secondary);
  font-size: 0.78rem;
}
.chat-typing.is-hidden { display: none; }
.chat-typing-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-muted);
  animation: chatTyping 1.2s infinite ease-in-out;
}
.chat-typing-dot:nth-child(2) { animation-delay: 0.2s; }
.chat-typing-dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes chatTyping {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* --- input --- */
.chat-input-area {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  padding: 0.6rem;
  border-top: 1px solid var(--border-color);
  background: var(--bg-secondary);
}
.chat-input {
  flex: 1;
  resize: none;
  max-height: 140px;
  padding: 0.5rem 0.7rem;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font: inherit;
  font-size: 0.9rem;
  line-height: 1.4;
}
.chat-input:focus {
  outline: none;
  border-color: var(--accent-color);
  box-shadow: 0 0 0 3px var(--accent-subtle);
}
.chat-send-btn {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}


/* ========== login.css ========== */
/* login.css — authenticated-login overlay (idea #1078).
   Uses the docs design tokens (design-tokens.css). Dark-theme only, matches the
   rest of the portal. */

/* When auth is active, the overlay covers the app entirely. */
body.cp-auth-active .portal-app { display: none; }

.cp-auth-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--bg-primary, #0d1117);
  overflow-y: auto;
}
.cp-auth-overlay.is-hidden { display: none; }

.cp-auth-card {
  width: 100%;
  max-width: 380px;
  background: var(--bg-secondary, #161b22);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-lg, 12px);
  box-shadow: var(--shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.4));
  padding: 28px 26px 24px;
}

.cp-auth-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  color: var(--text-primary, #e6edf3);
  margin-bottom: 18px;
}
.cp-auth-brand i { color: var(--accent-color, #58a6ff); }

.cp-auth-title {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--text-primary, #e6edf3);
  margin: 0 0 4px;
}
.cp-auth-sub {
  font-size: 0.85rem;
  color: var(--text-secondary, #8b949e);
  margin: 0 0 18px;
}

.cp-auth-step.is-hidden { display: none; }

.cp-auth-label {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary, #8b949e);
  margin: 12px 0 6px;
}

.cp-auth-input {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg-tertiary, #21262d);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  color: var(--text-primary, #e6edf3);
  font-size: 14px;
  padding: 10px 12px;
  transition: border-color var(--transition, 0.15s ease), box-shadow var(--transition, 0.15s ease);
}
.cp-auth-input:focus {
  outline: none;
  border-color: var(--accent-color, #58a6ff);
  box-shadow: 0 0 0 3px var(--accent-subtle, rgba(88, 166, 255, 0.1));
}

.cp-auth-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.82rem;
  color: var(--text-secondary, #8b949e);
  margin: 14px 0 4px;
}

.cp-auth-btn {
  width: 100%;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm, 6px);
  font-weight: 500;
  font-size: 14px;
  padding: 10px 14px;
  margin-top: 18px;
  cursor: pointer;
  transition: background var(--transition, 0.15s ease), border-color var(--transition, 0.15s ease);
}
.cp-auth-btn:disabled { opacity: 0.6; cursor: default; }
.cp-auth-btn-primary { background: var(--accent-color, #58a6ff); color: #0d1117; }
.cp-auth-btn-primary:hover:not(:disabled) { background: var(--accent-hover, #79c0ff); }

.cp-auth-btn-sso {
  background: var(--bg-tertiary, #21262d);
  border-color: var(--border-color, #30363d);
  color: var(--text-primary, #e6edf3);
  margin-top: 10px;
}
.cp-auth-btn-sso:hover { background: var(--bg-elevated, #1c2129); }

.cp-auth-links {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 14px;
}
.cp-auth-links a {
  font-size: 0.82rem;
  color: var(--accent-color, #58a6ff);
  text-decoration: none;
}
.cp-auth-links a:hover { text-decoration: underline; }

.cp-auth-error {
  background: rgba(248, 81, 73, 0.12);
  color: var(--danger, #f85149);
  border: 1px solid rgba(248, 81, 73, 0.3);
  border-radius: var(--radius-sm, 6px);
  font-size: 0.82rem;
  padding: 8px 10px;
  margin-bottom: 10px;
}
.cp-auth-error.is-hidden { display: none; }

.cp-auth-note {
  background: var(--accent-subtle, rgba(88, 166, 255, 0.1));
  color: var(--text-primary, #e6edf3);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  font-size: 0.82rem;
  padding: 8px 10px;
  margin-bottom: 10px;
}
.cp-auth-note.is-hidden { display: none; }

.cp-auth-divider {
  display: flex;
  align-items: center;
  text-align: center;
  color: var(--text-muted, #6e7681);
  font-size: 0.75rem;
  margin: 18px 0 4px;
}
.cp-auth-divider::before,
.cp-auth-divider::after {
  content: '';
  flex: 1;
  border-bottom: 1px solid var(--border-color, #30363d);
}
.cp-auth-divider span { padding: 0 10px; }
.cp-auth-sso.is-hidden { display: none; }


/* ========== portal-layout.css ========== */
/* portal-layout.css — full-page layout (idea #1963).

   Turns the portal from a single narrow stacked column into a page that USES the
   width: a centered content cap on the shell, plus responsive multi-column grids
   for the card/list views. Loads right after portal.css in the clientPortalCss
   cascade so these width rules win without !important. The remote-view rules are
   id-scoped (#view-remote …) because remote.css loads AFTER this file
   (alphabetical) and would otherwise re-flatten the station grid.

   Mobile (<768px) and the base single-column behaviour are untouched — every
   multi-column rule sits behind a min-width breakpoint. */

/* Centered content cap: fill the page but don't stretch uncomfortably wide on
   large monitors. The topbar + nav stay full-bleed (full-width chrome, centered
   content — the docs/PSA idiom). */
.portal-shell {
  --portal-max-width: 1600px;
}

/* --- Dashboard / request action cards -------------------------------------- */
/* Wrapped in .action-grid in index.html so the cards flow into a responsive
   grid instead of stacking full-width. */
.action-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
  margin-bottom: 10px;
}
/* .action-card defaults to display:block + margin-bottom for the stacked layout;
   neutralise that inside a grid and let cards share a row height. */
.action-grid .action-card {
  margin-bottom: 0;
  height: 100%;
}

/* --- Wide-screen multi-column list/card views ------------------------------ */
@media (min-width: 1100px) {
  /* Ticket rows, user cards, invoices/payments flow into columns rather than one
     tall single-file list. Base rules live in portal.css (loaded earlier), so
     ordering alone lets these win. */
  #tickets-container,
  .user-directory,
  .invoice-list,
  .payment-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(440px, 1fr));
    gap: 8px;
    align-items: start;
  }

  /* Remote station cards — grid only the LEAF card containers: the flat list, or
     the per-company station list when a user has computers at several companies.
     Never grid the .remote-company-group wrapper itself. Id-scoped to beat
     remote.css, which loads after this file. */
  #view-remote .remote-company-stations,
  #view-remote .remote-stations:not(:has(.remote-company-group)) {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
    gap: 10px;
  }

  /* Roomier key/value grids now that there's width for them. */
  .user-meta {
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  }
  .detail-grid {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  }
}

@media (min-width: 1440px) {
  #tickets-container,
  .user-directory,
  .invoice-list,
  .payment-list {
    grid-template-columns: repeat(auto-fill, minmax(480px, 1fr));
  }
}


/* ========== remote.css ========== */
/* remote.css — client remote-access view + in-page viewer (idea #1078). Portal tokens. */

.portal-view-head { margin-bottom: 16px; }
.portal-view-head h2 {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--text-primary, #e6edf3);
  margin: 0 0 4px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.portal-view-head h2 i { color: var(--accent-color, #58a6ff); }
.portal-view-sub { font-size: 0.85rem; color: var(--text-secondary, #8b949e); margin: 0; }

.remote-stations { display: flex; flex-direction: column; gap: 10px; }

/* Company grouping (idea #1619): a login assigned computers at more than one company sees a header per
   company, its stations listed beneath. Single-company users are rendered flat (no header). */
.remote-company-group { display: flex; flex-direction: column; gap: 10px; }
.remote-company-group + .remote-company-group { margin-top: 18px; }
.remote-company-header {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary, #8b949e);
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border-color, #30363d);
}
.remote-company-header i { color: var(--accent-color, #58a6ff); }
.remote-company-stations { display: flex; flex-direction: column; gap: 10px; }

.remote-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--bg-secondary, #161b22);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-md, 8px);
  padding: 14px 16px;
}
.remote-card-main { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap; }
/* Real bug fixed under idea #2024: this wrapper had no rule at all, unlike its
   sibling .remote-card-main — a station with multiple RDP targets rendered its
   buttons with zero gap between them. */
.remote-card-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.remote-host {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary, #e6edf3);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.remote-host i { color: var(--text-secondary, #8b949e); }
.remote-state { font-size: 12px; color: var(--text-secondary, #8b949e); }
.remote-inuse {
  font-size: 12px;
  color: var(--warning, #d29922);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

/* Status badge (station-modal pill pattern): tinted background + solid text. Colours per
   the "safe to join?" semantic — yellow = someone is actively using it (caution), green =
   idle/available. */
.remote-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 2px 9px;
  border-radius: 11px;
  flex: 0 0 auto;
}
.remote-badge.state-active { background: var(--warning-subtle); color: var(--warning); }
.remote-badge.state-idle { background: var(--success-subtle); color: var(--success); }
.remote-badge.state-nobody { background: var(--accent-subtle); color: var(--accent-color); }
.remote-badge.state-offline { background: var(--danger-subtle); color: var(--danger); }

/* Big Join button */
.remote-join {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent-color, #58a6ff);
  color: #0d1117;
  border: none;
  border-radius: var(--radius-sm, 6px);
  font-size: 15px;
  font-weight: 600;
  padding: 10px 22px;
  cursor: pointer;
  transition: background var(--transition, 0.15s ease);
}
.remote-join:hover:not(.is-disabled) { background: var(--accent-hover, #79c0ff); }
.remote-join.is-disabled { background: var(--bg-tertiary, #21262d); color: var(--text-muted, #6e7681); cursor: default; }

/* ===== In-page viewer overlay ===== */
.remote-viewer {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  flex-direction: column;
  background: #000;
}
.remote-viewer.is-hidden { display: none; }

.rv-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 14px;
  background: var(--bg-secondary, #161b22);
  border-bottom: 1px solid var(--border-color, #30363d);
  flex: 0 0 auto;
}
.rv-title { font-weight: 600; color: var(--text-primary, #e6edf3); display: inline-flex; align-items: center; gap: 8px; }
.rv-title i { color: var(--accent-color, #58a6ff); }
.rv-state { font-size: 12px; color: var(--text-secondary, #8b949e); }
.rv-state.ok { color: var(--success, #3fb950); }
.rv-state.bad { color: var(--danger, #f85149); }
.rv-actions { margin-left: auto; display: flex; gap: 8px; }
.rv-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--bg-tertiary, #21262d);
  color: var(--text-primary, #e6edf3);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  font-size: 13px;
  padding: 7px 12px;
  cursor: pointer;
}
.rv-btn:hover { background: var(--bg-elevated, #1c2129); }
.rv-close { background: var(--danger, #f85149); border-color: var(--danger, #f85149); color: #fff; }
.rv-close:hover { filter: brightness(1.1); }

.rv-stage { position: relative; flex: 1 1 auto; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.rv-screen { position: relative; width: 100%; height: 100%; }
/* The synthetic station-pointer overlay (.rv-cursor, idea #1227) and its `cursor: none` companions
   lived here. They existed only for the RFB path — the fan-out hub absorbed noVNC's Cursor
   pseudo-encoding, so the agent had to push the pointer position out-of-band (NWCTL cursor=x,y) for
   the viewer to draw. ironrdp-web has never needed any of it (it delivers the real pointer as a CSS
   `cursor` on the canvas via setCursorStyleCallback), so all three rules were already scoped OFF the
   RDP path and went with the VNC viewer in idea #2548. */
.rv-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  font-size: 15px;
}
.rv-overlay.is-hidden { display: none; }
/* RDP connecting modal (idea #1356): spinner stacked above the "Connecting to HOST…" label. */
.rv-overlay.rv-overlay-rdp { flex-direction: column; gap: 14px; }
.rdp-spinner {
  width: 38px; height: 38px;
  border: 3px solid rgba(255, 255, 255, 0.18);
  border-top-color: var(--accent-color, #58a6ff);
  border-radius: 50%;
  animation: rdp-spin 0.8s linear infinite;
}
@keyframes rdp-spin { to { transform: rotate(360deg); } }

/* Native-RDP self-service viewer (idea #1356) — sits in the shared remote viewer overlay. */
.remote-join-rdp { margin-left: 6px; }
.rdp-login {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 320px;
  max-width: 90%;
  margin: auto;
  padding: 22px;
  background: #161b22;
  border: 1px solid #30363d;
  border-radius: 10px;
  color: #e6edf3;
}
.rdp-login-title { font-size: 15px; font-weight: 700; margin-bottom: 8px; }
.rdp-login label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: #8b949e; margin-top: 6px; }
.rdp-login .rdp-opt { text-transform: none; letter-spacing: 0; color: #6e7681; }
.rdp-login input {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  padding: 8px 10px;
  font-size: 14px;
}
.rdp-login input:focus { outline: none; border-color: var(--accent-color); box-shadow: 0 0 0 3px var(--accent-subtle); }
.rdp-connect-btn {
  margin-top: 14px;
  background: var(--accent-color);
  color: #04122b;
  border: none;
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
}
.rdp-connect-btn:hover { background: var(--accent-hover); }
.rdp-login-note { margin-top: 10px; font-size: 11px; color: var(--text-muted); line-height: 1.4; }
/* Rejected-sign-in banner in the RDP prompt (idea #1356). */
.rdp-login-error {
  margin: 4px 0 6px; padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--danger-subtle);
  border: 1px solid var(--danger);
  color: var(--danger); font-size: 12px; line-height: 1.4;
}
/* Fill the stage so the canvas SCALES to the workspace (idea #1897 follow-up: at a zoom != 100% the
   negotiated resolution differs from the viewport, so the canvas must stretch up/down to fill). The
   negotiated resolution is derived FROM the stage aspect (rdpViewportSize divides both dims by the
   same zoom), so filling introduces no meaningful distortion, and mouse mapping stays exact because
   it uses getBoundingClientRect (displayed box) vs canvas.width (backing store). */
#rdp-canvas { display: block; width: 100%; height: 100%; object-fit: contain; margin: auto; outline: none; cursor: default; }

/* Soft-keyboard relay input (idea #2259) — invisible but genuinely FOCUSABLE, which is the entire
   point: mobile Safari/Chrome only raise the on-screen keyboard for a focused <input>, never for a
   <canvas>. display:none / visibility:hidden would both defeat that (a hidden element can't take
   focus, so the keyboard would never appear) — so this stays laid out and focusable, just visually
   nulled out. font-size MUST stay >=16px: iOS Safari auto-zooms the whole page on focus of any input
   below that, which would visibly yank the viewport on every "Show keyboard" tap. */
.rdp-soft-kbd {
  position: absolute;
  bottom: 0; left: 0;
  width: 1px; height: 1px;
  min-width: 0; min-height: 0;
  margin: 0; padding: 0; border: none;
  opacity: 0.01;
  font-size: 16px;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  pointer-events: none;
}

/* Keyboard-detached cue (idea #2258). Keys only reach the remote while #rdp-canvas holds DOM focus, but
   the mouse never needs focus — so focus loss produced a working mouse and a silently dead keyboard. This
   chip is the missing feedback. Bottom-center so it never covers the remote's title bar or system tray,
   and pointer-events:none so it can't itself intercept the click that fixes the problem. */
.rdp-kbd-hint {
  position: absolute;
  bottom: 18px; left: 50%;
  transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px;
  background: var(--bg-secondary, #161b22);
  border: 1px solid var(--accent-color, #58a6ff);
  border-radius: 12px;
  box-shadow: var(--shadow-sm, 0 2px 8px rgba(0, 0, 0, 0.4));
  color: var(--text-primary, #e6edf3);
  font-size: 13px; font-weight: 500;
  pointer-events: none;
  animation: rdp-kbd-hint-in 0.18s ease-out;
}
.rdp-kbd-hint i { color: var(--accent-color, #58a6ff); }
.rdp-kbd-hint.is-hidden { display: none; }
@keyframes rdp-kbd-hint-in {
  from { opacity: 0; transform: translate(-50%, 6px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* Zero-click RDP viewer (idea #1356): minimal chrome — just the host · app title. */
#remote-viewer.rv-rdp #rv-state { display: none; }
.remote-join-rdp { margin-left: 6px; }

/* Ctrl+Alt+Del — RDP path only; the RFB viewer has no equivalent wired here. This was previously
   hidden FOR .rv-rdp (i.e. hidden in every real session, since RDP has been the only client path
   since idea #1883) — idea #1356 lumped it into the "minimal chrome" rule above by mistake. Idea
   #2258 fixed the click handler (rdpSendCad(), rdp.js) but left this selector inverted, so the fix
   stayed unreachable until idea #2550. It's a functional escape hatch, not decorative chrome. */
#remote-viewer:not(.rv-rdp) [data-action="remote-cad"] { display: none; }

/* Full-screen button (idea #1779) — RDP path only. Hidden until an RDP session owns the overlay
   (fullscreen renegotiates the remote desktop via RDP.session.resize(); noVNC has no such path). */
#remote-viewer.rv-rdp .rv-fullscreen-btn { display: inline-flex; }

/* "Paste to remote" clipboard button (idea #1866) — RDP path only. Manual fallback for browsers that
   block/deny the passive clipboard poll; the RFB viewer doesn't sync clipboards, so hide it there. */
#remote-viewer.rv-rdp .rv-paste-btn { display: inline-flex; }

/* Mute/unmute remote sound (RDPSND, idea #1897) — RDP path only (RFB carries no audio). Hidden by
   default, shown once an RDP session owns the overlay. Muted state dims the icon so it's obvious. */
.rv-mute-btn { display: none; }
#remote-viewer.rv-rdp .rv-mute-btn { display: inline-flex; }
.rv-mute-btn.rv-muted { color: var(--text-secondary, #8b949e); }
.rv-mute-btn.rv-muted i { opacity: 0.7; }

/* Resolution zoom controls (idea #1897 follow-up) — RDP path only (the RFB viewer has no
   resolution renegotiation). Hidden until an RDP session owns the overlay. The level chip is a
   reset-to-100% button; buttons disable at the ends of the zoom ladder. */
.rv-zoom-btn, .rv-zoom-level { display: none; }
#remote-viewer.rv-rdp .rv-zoom-btn { display: inline-flex; }
#remote-viewer.rv-rdp .rv-zoom-level { display: inline-flex; }
.rv-zoom-level { min-width: 3.4em; justify-content: center; font-variant-numeric: tabular-nums; }
.rv-btn:disabled { opacity: 0.4; cursor: default; }
.rv-btn:disabled:hover { background: var(--bg-tertiary, #21262d); }

/* Top-center "you are in a remote session" pill + Exit (idea #1779). Only shown in OS full screen,
   where the normal top bar is easy to overlook — makes it obvious this is a remote desktop and how
   to get out. pointer-events kept so the Exit button is clickable over the canvas. */
.rv-session-banner {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  display: none;
  align-items: center;
  gap: 10px;
  padding: 7px 8px 7px 14px;
  background: rgba(13, 17, 23, 0.82);
  border: 1px solid var(--border-color, #30363d);
  border-radius: 999px;
  color: var(--text-primary, #e6edf3);
  font-size: 13px;
  font-weight: 600;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
  pointer-events: auto;
}
.rv-session-banner i { color: var(--accent-color, #58a6ff); }
#remote-viewer.rv-fullscreen .rv-session-banner { display: inline-flex; }

/* Drag handle (idea #2347) — the pill is the only chrome in full screen AND it sits exactly where a
   Windows title bar / ribbon lives, so the user has to be able to move it. The handle is the icon +
   label only (never the buttons); rdpBanner.js takes over positioning on first move. */
.rv-session-drag {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: grab;
  /* A drag must not select the label or scroll/zoom the page on touch. */
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}
.rv-session-grip { color: var(--text-muted, #6e7681) !important; font-size: 12px; }
.rv-session-banner.rv-banner-dragging { cursor: grabbing; }
.rv-session-banner.rv-banner-dragging .rv-session-drag { cursor: grabbing; }
/* Once moved, the inline left/top own the position — drop the centring transform, which would
   otherwise offset the pill by half its own width from wherever it was dropped. */
.rv-session-banner.rv-banner-moved { transform: none; }
/* In OS full screen the top connection bar gets out of the way — the center pill is the sole chrome. */
#remote-viewer.rv-fullscreen .rv-bar { display: none; }
.rv-session-btn,
.rv-session-exit {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: none;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 12px;
  cursor: pointer;
}
.rv-session-btn { background: rgba(255, 255, 255, 0.14); color: var(--text-primary, #e6edf3); }
.rv-session-btn:hover { background: rgba(255, 255, 255, 0.22); }
/* Zoom/mute controls added to the full-screen banner (idea #1897) — dim at the zoom-ladder ends. */
.rv-session-btn:disabled { opacity: 0.4; cursor: default; }
.rv-session-btn:disabled:hover { background: rgba(255, 255, 255, 0.14); }
.rv-session-btn.rv-muted { color: var(--text-secondary, #8b949e); }
.rv-session-exit { background: var(--danger, #f85149); color: #fff; }
.rv-session-exit:hover { filter: brightness(1.1); }

/* ── Remote-access header row + "Report a problem" button (idea #1878) ─────────────────────────── */
.portal-view-head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.remote-report-btn {
  flex: none;
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--bg-tertiary, #21262d);
  color: var(--text-secondary, #8b949e);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  padding: 8px 12px;
  font-size: 13px; font-weight: 500;
  cursor: pointer;
}
.remote-report-btn i { color: var(--warning, #d29922); }
.remote-report-btn:hover { background: var(--bg-elevated, #1c2129); color: var(--text-primary, #e6edf3); border-color: var(--text-muted, #6e7681); }

/* ── "Session complete" card (idea #1878) — centered in #rv-screen after a session ends ────────── */
.rdp-complete {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 420px; max-width: 90%;
  box-sizing: border-box;
  padding: 26px;
  background: var(--bg-secondary, #161b22);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-md, 10px);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
  color: var(--text-primary, #e6edf3);
  text-align: center;
}
.rdp-complete-icon { font-size: 40px; color: var(--success, #3fb950); margin-bottom: 10px; }
.rdp-complete .rdp-complete-icon .fa-plug-circle-xmark { color: var(--danger, #f85149); }
.rdp-complete-title { font-size: 18px; font-weight: 700; margin-bottom: 6px; }
.rdp-complete-sub { font-size: 13px; color: var(--text-secondary, #8b949e); line-height: 1.5; margin-bottom: 16px; }
.rdp-complete-fb { text-align: left; margin: 0 0 4px; }
.rdp-complete-fb-label { display: block; font-size: 12px; color: var(--text-secondary, #8b949e); margin-bottom: 6px; }
.rdp-complete-fb-input {
  width: 100%; box-sizing: border-box;
  background: var(--bg-primary, #0d1117);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  color: var(--text-primary, #e6edf3);
  padding: 8px 10px; font-size: 13px; font-family: inherit;
  resize: vertical;
}
.rdp-complete-fb-input:focus { outline: none; border-color: var(--accent-color); box-shadow: 0 0 0 3px var(--accent-subtle); }
.rdp-complete-fb-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.rdp-complete-send { margin-top: 0 !important; display: inline-flex; align-items: center; gap: 6px; }
.rdp-complete-send:disabled { opacity: 0.6; cursor: default; }
.rdp-complete-noask { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-secondary, #8b949e); cursor: pointer; }
.rdp-complete-thanks { font-size: 13px; color: var(--success, #3fb950); display: inline-flex; align-items: flex-start; gap: 8px; text-align: left; line-height: 1.4; }
.rdp-complete-actions { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 18px; flex-wrap: wrap; }
.rdp-complete-reconnect { margin-top: 0 !important; display: inline-flex; align-items: center; gap: 6px; }
.rdp-complete-back {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-tertiary, #21262d);
  color: var(--text-primary, #e6edf3);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  padding: 10px 14px; font-size: 14px; font-weight: 500; cursor: pointer;
}
.rdp-complete-back:hover { background: var(--bg-elevated, #1c2129); }

/* Textarea inside the shared cm-* modal for the list-level "Report a problem" (idea #1878). */
.cm-body-form { display: block; }
.cm-body-form .rdp-report-label { display: block; font-size: 13px; color: var(--text-secondary, #8b949e); margin-bottom: 8px; line-height: 1.5; }

/* ── RDP performance HUD (idea #2083) ─────────────────────────────────────────────────────────────
   Opt-in diagnostic overlay (?rdpdiag=1) that reports whether a slow session is starved of bytes or
   bottlenecked painting them. Bottom-left so it clears the top bar and the centred session banner;
   pointer-events:none so it can never intercept a click meant for the remote desktop. */
.rdp-stats {
  position: absolute; left: 10px; bottom: 10px; z-index: 12;
  display: flex; gap: 10px; flex-wrap: wrap;
  padding: 5px 9px;
  background: rgba(0, 0, 0, 0.72);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  color: var(--text-primary, #e6edf3);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px; line-height: 1.5; letter-spacing: 0.02em;
  pointer-events: none; user-select: none;
}
.rdp-stats .rdp-stats-k {
  color: var(--text-secondary, #8b949e);
  text-transform: uppercase; font-size: 9px; letter-spacing: 0.06em;
}
.rdp-stats .rdp-stats-warn { color: var(--warning, #d29922); font-weight: 600; }
.rdp-stats .rdp-stats-bad { color: var(--danger, #f85149); font-weight: 600; }

/* Picture-quality dropdown (idea #2083) — sits beside the zoom controls. Styled to match .rv-btn so
   the toolbar reads as one row; the native <select> is kept (rather than a custom menu) so keyboard
   and screen-reader behaviour come for free. */
.rv-quality {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0 8px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid var(--border-color, #30363d);
  border-radius: var(--radius-sm, 6px);
  color: var(--text-primary, #e6edf3);
}
.rv-quality > i { font-size: 12px; color: var(--text-secondary, #8b949e); }
.rv-quality-select {
  appearance: none; -webkit-appearance: none;
  background: transparent; border: 0; outline: none;
  color: inherit; font-family: inherit; font-size: 12px; font-weight: 500;
  padding: 6px 16px 6px 0; cursor: pointer;
  /* Chevron drawn in the padding gap so we don't need a second element. */
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 6px center, right 2px center;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.rv-quality-select:focus-visible { outline: 2px solid var(--accent-color, #58a6ff); outline-offset: 2px; }
/* The popup list renders with the OS/browser theme, so force readable colours on the options. */
.rv-quality-select option { background: var(--bg-secondary, #161b22); color: var(--text-primary, #e6edf3); }
