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

/* Design tokens (--clr-*, --radius) live in css/styles/tokens.css, which every
   page linking this file must load first (#2333). The menu widths stay here:
   they size the nav chrome this stylesheet owns, and no other page needs them. */
:root {
  --menu-width-expanded: 246px;
  --menu-width-collapsed: 72px;
  --menu-width: var(--menu-width-expanded);
}

html {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

body {
  font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
  background: var(--clr-bg);
  color: var(--clr-text);
  line-height: 1.6;
  padding: 2rem;
  width: 100%;
  max-width: none;
  margin: 0 auto;
}

body.auth-authenticated {
  min-height: 100vh;
  padding: 1rem 1rem 1rem calc(var(--menu-width) + 1rem);
}

body.auth-authenticated.menu-collapsed {
  --menu-width: var(--menu-width-collapsed);
}

body.auth-guest {
  min-height: 100vh;
}

a {
  color: inherit;
}

#app-header {
  margin-bottom: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 1rem;
}

body.auth-authenticated #app-header {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--menu-width);
  border-right: 1px solid var(--clr-border);
  background: var(--clr-surface);
  box-shadow: 12px 0 28px color-mix(in srgb, var(--clr-shadow), transparent 65%);
  z-index: 120;
  padding: 0.75rem 0.5rem;
}

#header-divider {
  margin: 0 0 0.85rem;
  border: none;
  border-top: 1px solid var(--clr-border);
}

body.auth-authenticated #header-divider {
  display: none;
}

#header-actions {
  display: flex;
  align-items: stretch;
  justify-content: flex-start;
  gap: 0.5rem;
  flex-wrap: nowrap;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

#menu-brand-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.45rem;
  width: 100%;
}

#app-logo-placeholder {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 30px;
}

#app-logo-placeholder .brand-img {
  display: none;
}

#app-logo-placeholder .brand-full {
  height: 45px;
  width: auto;
  max-width: 100%;
}

#app-logo-placeholder .brand-mark {
  height: 28px;
  width: 28px;
}

/* Show exactly one logo per theme + collapse state */
:root[data-theme="light"] body:not(.menu-collapsed) #app-logo-placeholder .brand-full.brand-light,
:root[data-theme="dark"] body:not(.menu-collapsed) #app-logo-placeholder .brand-full.brand-dark,
:root[data-theme="light"] body.menu-collapsed #app-logo-placeholder .brand-mark.brand-light,
:root[data-theme="dark"] body.menu-collapsed #app-logo-placeholder .brand-mark.brand-dark {
  display: block;
}

.app-page-title {
  margin: 0 0 0.85rem;
  font-size: clamp(1.25rem, 1.8vw, 1.6rem);
  line-height: 1.15;
  font-weight: 700;
  color: var(--clr-text);
}

#app-top-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 0 0 0.85rem;
}

#app-top-row .app-page-title {
  margin: 0;
  margin-right: auto;
}

#btn-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  min-width: 30px;
  min-height: 30px;
  height: 30px;
  padding: 0;
}

.menu-arrow-icon {
  display: inline-flex;
  width: 14px;
  height: 14px;
}

.menu-arrow-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

body.auth-authenticated.menu-collapsed .menu-arrow-icon svg {
  transform: rotate(180deg);
}

#theme-toggle {
  display: inline-flex;
  position: relative;
  align-items: center;
  justify-content: flex-start;
  gap: 0.5rem;
  min-height: 38px;
  height: 38px;
  padding: 0.35rem 0.55rem;
  background: transparent;
  color: var(--clr-text);
  border: none;
  border-radius: 0;
  box-shadow: none;
  font-size: 0.84rem;
  font-weight: 600;
  font-family: inherit;
  line-height: 1;
  white-space: nowrap;
  width: 100%;
}

#theme-toggle:hover,
#theme-toggle:focus-visible {
  background: var(--clr-primary-fill);
  color: #fff;
  border-color: var(--clr-primary);
}

#theme-toggle .theme-toggle-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}

#theme-toggle .theme-toggle-icon::before {
  content: "";
  width: 14px;
  height: 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #fbbf24, #f97316);
  box-shadow: inset -0.13rem -0.13rem 0 0 rgba(255, 255, 255, 0.5);
}

:root[data-theme="dark"] #theme-toggle .theme-toggle-icon::before {
  background: linear-gradient(135deg, #bfdbfe, #60a5fa);
  box-shadow: inset -0.13rem -0.13rem 0 0 rgba(15, 23, 42, 0.42);
}

/* ---------- Navigation Menu ---------- */
#main-nav {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
  flex-direction: column;
  flex-wrap: nowrap;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

#auth-controls {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}

#header-auth-slot {
  display: flex;
  align-items: stretch;
  margin-top: 0.2rem;
  width: 100%;
}

#auth-center-slot {
  width: 100%;
}

#auth-user {
  font-size: 0.85rem;
  font-weight: 600;
  margin-right: 0.2rem;
}

#auth-controls input {
  height: 38px;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius);
  background: var(--clr-input-bg);
  color: var(--clr-text);
  font-size: 0.88rem;
}

.auth-input-label {
  width: 100%;
  margin-bottom: -0.35rem;
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--clr-muted);
}

#auth-inline-error {
  width: 100%;
  font-size: 0.84rem;
  color: var(--clr-error-text);
  border: 1px solid var(--clr-error-border);
  background: var(--clr-error-bg);
  border-radius: var(--radius);
  padding: 0.45rem 0.6rem;
  line-height: 1.35;
}

#auth-inline-error.auth-warning {
  color: var(--clr-warning-text);
  border-color: var(--clr-warning-border);
  background: var(--clr-warning-bg);
}

#auth-first-name.auth-input-error,
#auth-surname.auth-input-error,
#auth-email.auth-input-error,
#auth-password.auth-input-error,
#auth-confirm-password.auth-input-error {
  border-color: var(--clr-error-border);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--clr-error-border), transparent 65%);
}

#auth-email {
  width: 180px;
}

#auth-password,
#auth-confirm-password {
  width: 150px;
}

#auth-forgot-password {
  font-size: 0.82rem;
  color: var(--clr-primary);
  text-decoration: none;
  text-align: right;
  width: 100%;
  margin-top: -0.2rem;
}

#auth-forgot-password:hover {
  text-decoration: underline;
}

#btn-auth-submit,
#btn-auth-logout {
  min-height: 38px;
  padding: 0.45rem 0.9rem;
  font-size: 0.88rem;
}

/* Sign-in button loading state (issue #2518): an in-button spinner + label swap
   while the auth request is in flight, so the form never looks frozen. Reuses the
   loader-spin keyframe; currentColor keeps it legible on the button's fill. */
#btn-auth-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.auth-submit-spinner {
  display: none;
  width: 15px;
  height: 15px;
  border: 2px solid color-mix(in srgb, currentColor, transparent 65%);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: loader-spin 0.7s linear infinite;
  flex: 0 0 auto;
}

#btn-auth-submit.is-loading .auth-submit-spinner {
  display: inline-block;
}

#auth-gate {
  min-height: calc(100vh - 8rem);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 0;
}

#auth-gate-card {
  width: min(100%, 460px);
  padding: 2.25rem;
  border: 1px solid var(--clr-border);
  border-radius: 20px;
  background:
    radial-gradient(circle at top right, color-mix(in srgb, var(--clr-primary), transparent 86%), transparent 45%),
    var(--clr-surface);
  box-shadow: var(--clr-shadow);
}

#auth-gate-eyebrow {
  display: flex;
  justify-content: center;
  margin-bottom: 0.65rem;
}

#auth-gate-eyebrow .brand-img {
  display: none;
  height: clamp(40px, 6vw, 56px);
  width: auto;
}

:root[data-theme="light"] #auth-gate-eyebrow .brand-light,
:root[data-theme="dark"] #auth-gate-eyebrow .brand-dark {
  display: block;
}

#auth-gate-title {
  margin-bottom: 0.45rem;
  font-size: clamp(1.9rem, 3vw, 2.4rem);
  line-height: 1.1;
}

#auth-gate-copy {
  margin-bottom: 1.5rem;
  color: var(--clr-muted);
}

body.auth-guest #main-nav,
body.auth-guest #header-divider,
body.auth-guest #btn-menu-toggle,
body.auth-guest #menu-brand-row,
body.auth-guest #app-shell,
body.auth-guest #auth-user,
body.auth-guest #btn-auth-logout,
body.auth-guest #header-auth-slot,
body.auth-guest #top-profile-wrap {
  display: none !important;
}

body.auth-authenticated #header-auth-slot #auth-controls {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.5rem;
}

body.auth-authenticated #header-auth-slot .auth-input-label {
  display: none;
}

body.auth-authenticated.menu-collapsed #app-logo-placeholder {
  flex: 0 0 34px;
  width: 34px;
  min-width: 34px;
  padding: 0;
  justify-content: center;
}

body.auth-authenticated.menu-collapsed #theme-toggle {
  width: 44px;
  min-width: 44px;
  padding: 0;
  justify-content: center;
  margin: 0 auto;
}

body.auth-authenticated.menu-collapsed #theme-toggle-label,
body.auth-authenticated.menu-collapsed .auth-btn-label {
  display: none;
}

body.auth-authenticated.menu-collapsed #btn-auth-logout {
  width: 44px;
  min-width: 44px;
  padding: 0;
  justify-content: center;
  margin: 0 auto;
}

body.auth-authenticated.menu-collapsed #btn-auth-logout .auth-btn-icon {
  margin-right: 0;
}

#btn-auth-logout {
  display: inline-flex;
  position: relative;
  align-items: center;
  justify-content: flex-start;
  gap: 0.55rem;
  background: transparent;
  border: none;
  border-radius: 0;
  width: 100%;
  min-height: 44px;
  height: 44px;
  font-size: 0.9rem;
  font-weight: 600;
  font-family: inherit;
}

#btn-auth-logout:hover,
#btn-auth-logout:focus-visible {
  background: var(--clr-primary-fill);
  color: #fff;
  border-color: var(--clr-primary);
}

.auth-btn-icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
}

.auth-btn-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

#top-profile-wrap {
  position: relative;
  margin-left: 0;
  z-index: 220;
}

#project-switcher-wrap {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 0;
  margin-left: 0;
}

#project-switcher-button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 320px;
  min-height: 36px;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius, 0.6rem);
  background: var(--clr-surface);
  color: var(--clr-text);
  box-shadow: var(--clr-shadow);
  font-size: 0.86rem;
  cursor: pointer;
}

#project-switcher-button:hover:not(:disabled) {
  border-color: var(--clr-primary);
}

#project-switcher-button:disabled {
  cursor: default;
  opacity: 0.95;
}

.project-switcher-button-context {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  overflow: hidden;
}

.project-switcher-button-org {
  color: var(--clr-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 130px;
}

.project-switcher-button-sep {
  color: var(--clr-muted);
}

.project-switcher-button-project {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 160px;
}

.project-switcher-button-caret {
  color: var(--clr-muted);
  font-size: 0.7rem;
  line-height: 1;
}

#project-switcher-button:disabled .project-switcher-button-caret {
  display: none;
}

#project-switcher-hint {
  display: none;
}

/* --clr-warning was never defined, so both of these resolved to their literal
   fallback — and the two fallbacks were DIFFERENT colours (#f59e0b here,
   #b45309 below). Defining the token would have collapsed them into one. They
   are two roles, and both already have a token (#3155). */
#project-switcher-wrap.no-access #project-switcher-button {
  border-color: var(--clr-warning-border);
  background: color-mix(in srgb, var(--clr-warning-border), transparent 90%);
}

#project-switcher-wrap.no-access .project-switcher-button-project {
  color: var(--clr-warning-text);
  font-weight: 600;
}

/* This modal is short (two fields), so let the searchable option lists overflow
   the card instead of being clipped/scrolled by its overflow:auto — otherwise the
   Project list (last field) opens downward and is cut off at the card edge. The
   compound selector is needed to outweigh settings.css's later
   `.maintenance-task-modal-card { overflow: auto }

`. */
.maintenance-task-modal-card.project-switcher-modal-card {
  overflow: visible;
}

/* Container is focused on open for keyboard/Escape support; it is not a tabbable
   control, so suppress the focus ring on the card itself. */
.project-switcher-modal-card:focus {
  outline: none;
}

.project-switcher-modal-subtitle {
  margin: 0 0 0.85rem;
  font-size: 0.85rem;
}

.project-switcher-modal-field {
  display: grid;
  gap: 0.3rem;
}

.project-switcher-modal-hint {
  margin-top: 0.6rem;
  font-size: 0.82rem;
  min-height: 1.1rem;
}

#btn-profile-menu {
  width: 38px;
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--clr-border);
  background: var(--clr-surface);
  color: var(--clr-text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: 700;
  box-shadow: var(--clr-shadow);
  padding: 0;
}

#profile-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: 220px;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius);
  background: var(--clr-surface);
  box-shadow: var(--clr-shadow);
  padding: 0.45rem 0.6rem;
}

#profile-name,
#profile-email,
#profile-role {
  font-size: 0.85rem;
  color: var(--clr-text);
  white-space: nowrap;
  line-height: 1.35;
}

#profile-name {
  font-weight: 700;
}

#profile-email {
  color: var(--clr-muted);
  margin-top: 0.1rem;
}

#profile-role {
  margin-top: 0.35rem;
}

#btn-profile-edit {
  margin-top: 0.5rem;
}

.profile-menu-action {
  margin-top: 0.35rem;
  width: 100%;
  min-height: 34px;
  padding: 0.35rem 0.55rem;
  font-size: 0.84rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.profile-action-icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
}

.profile-action-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

#profile-edit-modal,
#profile-change-password-modal {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: grid;
  place-items: center;
}

#profile-edit-backdrop,
#profile-change-password-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.45);
}

#profile-edit-card,
#profile-change-password-card {
  position: relative;
  width: min(92vw, 420px);
  border: 1px solid var(--clr-border);
  border-radius: 14px;
  background: var(--clr-surface);
  box-shadow: var(--clr-shadow);
  padding: 1rem;
  display: grid;
  gap: 0.45rem;
}

#profile-edit-title,
#profile-change-password-title {
  margin: 0 0 0.2rem;
  font-size: 1.1rem;
}

#profile-edit-card label,
#profile-change-password-card label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--clr-muted);
}

#profile-edit-card input,
#profile-change-password-card input {
  width: 100%;
  min-height: 38px;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius);
  background: var(--clr-input-bg);
  color: var(--clr-text);
}

#profile-edit-error,
#profile-change-password-error {
  font-size: 0.84rem;
  color: var(--clr-error-text);
  border: 1px solid var(--clr-error-border);
  background: var(--clr-error-bg);
  border-radius: var(--radius);
  padding: 0.4rem 0.55rem;
}

#profile-edit-actions,
#profile-change-password-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.3rem;
}

body.auth-guest #app-header {
  justify-content: space-between;
  align-items: flex-start;
}

body.auth-guest #header-actions {
  align-items: flex-start;
  justify-content: space-between;
}

body.auth-guest #theme-toggle {
  width: auto;
  min-width: 0;
  min-height: 34px;
  height: 34px;
  padding: 0.25rem 0.45rem;
  font-size: 0.8rem;
  gap: 0.4rem;
}

body.auth-guest #auth-center-slot #auth-controls {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.8rem;
}

body.auth-guest #auth-center-slot #auth-controls input,
body.auth-guest #auth-center-slot #auth-controls button {
  width: 100%;
}

body.auth-guest #auth-center-slot #auth-email,
body.auth-guest #auth-center-slot #auth-password,
body.auth-guest #auth-center-slot #auth-confirm-password {
  width: 100%;
  height: 46px;
  padding: 0.7rem 0.85rem;
  font-size: 0.95rem;
}

body.auth-guest #auth-center-slot #btn-auth-submit {
  min-height: 46px;
  background: var(--clr-primary-fill);
  color: #fff;
}

body.auth-guest #auth-center-slot #btn-auth-submit:hover {
  background: var(--clr-primary-fill-hover);
}

/* First-run "Create Admin" holds the button until the password meter passes
   (#3076). Without this the gated button keeps its full primary fill and reads
   as clickable. Same treatment the invite / reset submit buttons already get
   from .auth-form button:disabled in auth.css. */
body.auth-guest #auth-center-slot #btn-auth-submit:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

body.auth-guest #auth-center-slot #btn-auth-submit:disabled:hover {
  background: var(--clr-primary-fill);
}

body.auth-authenticated #auth-gate {
  display: none;
}

body.auth-initializing #auth-gate,
body.auth-initializing #app-shell {
  display: none !important;
}

#page-loader {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--clr-bg);
  z-index: 9999;
  opacity: 1;
  transition: opacity 0.3s ease;
}

body.auth-initializing #page-loader {
  opacity: 1;
}

body:not(.auth-initializing) #page-loader {
  opacity: 0;
  pointer-events: none;
}

.loader-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--clr-border);
  border-top-color: var(--clr-primary);
  border-radius: 50%;
  animation: loader-spin 0.8s linear infinite;
}

@keyframes loader-spin {
  to {
    transform: rotate(360deg);
  }
}

.nav-item {
  position: relative;
  display: flex;
}

.nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.65rem;
  background: transparent;
  color: var(--clr-text);
  border: none;
  padding: 0.55rem 0.65rem;
  width: 100%;
  min-height: 44px;
  height: 44px;
  font-size: 0.9rem;
  font-weight: 600;
  font-family: inherit;
  line-height: 1;
  border-radius: 0;
  text-decoration: none;
  white-space: nowrap;
}

.nav-item.has-submenu > .nav-btn::after {
  content: "";
  margin-left: auto;
  width: 7px;
  height: 7px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.15s ease;
  flex: 0 0 auto;
}

.nav-item.open > .nav-btn::after {
  transform: rotate(135deg);
}

.nav-btn:hover,
.nav-btn.active {
  background: var(--clr-primary-fill);
  color: #fff;
  border-color: var(--clr-primary);
}

.nav-icon {
  display: inline-flex;
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}

.nav-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.nav-label {
  display: inline-flex;
  align-items: center;
}

body.auth-authenticated.menu-collapsed #main-nav {
  align-items: center;
  width: 44px;
  min-width: 44px;
  margin: 0 auto;
  overflow: visible;
}

body.auth-authenticated.menu-collapsed .nav-btn {
  justify-content: center;
  width: 44px;
  min-width: 44px;
  padding: 0;
  margin: 0 auto;
}

body.auth-authenticated.menu-collapsed .nav-item.has-submenu > .nav-btn::after {
  content: none;
}

body.auth-authenticated.menu-collapsed #header-auth-slot {
  width: 44px;
  min-width: 44px;
  margin: 0 auto;
}

body.auth-authenticated.menu-collapsed #header-auth-slot #auth-controls {
  width: 44px;
  align-items: center;
}

body.auth-authenticated.menu-collapsed .nav-label {
  display: none;
}

body.auth-authenticated #btn-menu-toggle {
  position: relative;
}

body.auth-authenticated:not(.menu-collapsed) #btn-menu-toggle:hover::before,
body.auth-authenticated:not(.menu-collapsed) #btn-menu-toggle:focus-visible::before {
  content: attr(data-tooltip);
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%);
  background: #111;
  color: #fff;
  border-radius: 6px;
  padding: 0.3rem 0.5rem;
  font-size: 0.78rem;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  z-index: 220;
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}

body.auth-authenticated.menu-collapsed .nav-btn,
body.auth-authenticated.menu-collapsed #theme-toggle,
body.auth-authenticated.menu-collapsed #btn-auth-logout,
body.auth-authenticated.menu-collapsed #btn-menu-toggle {
  position: relative;
}

body.auth-authenticated.menu-collapsed .nav-btn:hover::before,
body.auth-authenticated.menu-collapsed .nav-btn:focus-visible::before,
body.auth-authenticated.menu-collapsed #theme-toggle:hover::before,
body.auth-authenticated.menu-collapsed #theme-toggle:focus-visible::before,
body.auth-authenticated.menu-collapsed #btn-auth-logout:hover::before,
body.auth-authenticated.menu-collapsed #btn-auth-logout:focus-visible::before,
body.auth-authenticated.menu-collapsed #btn-menu-toggle:hover::before,
body.auth-authenticated.menu-collapsed #btn-menu-toggle:focus-visible::before {
  content: attr(data-tooltip);
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%);
  background: #111;
  color: #fff;
  border-radius: 6px;
  padding: 0.3rem 0.5rem;
  font-size: 0.78rem;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  z-index: 220;
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}

.submenu {
  display: block;
  position: static;
  list-style: none;
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  width: 100%;
  min-width: 0;
  z-index: 10;
  padding: 0;
  margin-top: 0.35rem;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transform: none;
  transform-origin: top;
  pointer-events: none;
  will-change: max-height, opacity;
  transition: max-height 0.24s ease, opacity 0.2s ease;
}

.nav-item.open .submenu {
  max-height: var(--submenu-open-height, 260px);
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

body.auth-authenticated:not(.menu-collapsed) .nav-item.has-submenu {
  flex-direction: column;
  width: 100%;
}

body.auth-authenticated:not(.menu-collapsed) .nav-item.has-submenu .submenu {
  position: static;
  top: auto;
  left: auto;
  width: 100%;
  min-width: 0;
  margin-top: 0.35rem;
}

body.auth-authenticated.menu-collapsed .submenu {
  display: none;
  position: absolute;
  top: 50%;
  left: calc(100% + 8px);
  transform: translateY(-50%);
  width: max-content;
  min-width: 160px;
  margin-top: 0;
  margin: 0;
  max-height: none !important;
  opacity: 0;
  overflow: visible;
  pointer-events: none;
  transition: opacity 0.15s ease;
  background: var(--clr-surface);
  border-radius: var(--radius);
  box-shadow: var(--clr-shadow);
  border: 1px solid var(--clr-border);
  z-index: 1000;
  padding: 0;
  list-style: none;
}

body.auth-authenticated.menu-collapsed .submenu li {
  margin: 0;
  padding: 0;
  display: block;
}

body.auth-authenticated.menu-collapsed .submenu li a {
  padding: 0.6rem 1rem;
}

body.auth-authenticated.menu-collapsed .nav-item.open .submenu {
  display: block;
  opacity: 1;
  pointer-events: auto;
  overflow: visible;
}

.submenu li a {
  display: block;
  padding: 0.5rem 1rem;
  text-decoration: none;
  color: var(--clr-text);
  font-size: 0.9rem;
  transition: background 0.1s;
  border-radius: 0;
  white-space: nowrap;
}

.submenu li a:hover,
.submenu li a.active {
  background: var(--clr-active);
  color: var(--clr-primary);
}

h2 {
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
}

.subtitle {
  color: var(--clr-muted);
  margin-top: 0.25rem;
}

.muted {
  color: var(--clr-muted);
  font-size: 0.875rem;
}

.hidden {
  display: none !important;
}

/* ---------- App View Panels ---------- */
[id^="view-"] {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  width: 100%;
}

/* Drag-over affordance, scoped to the card the files are dropped onto */
#folder-picker.is-drag-over {
  border-color: var(--clr-primary);
  background: color-mix(in srgb, var(--clr-primary), transparent 92%);
  box-shadow: 0 0 0 2px var(--clr-primary);
}

.btn-primary {
  background: var(--clr-primary-fill);
  color: #fff;
}

.btn-primary:hover {
  background: var(--clr-primary-fill-hover);
}

.btn-secondary {
  background: var(--clr-surface);
  border: 1px solid var(--clr-border);
  color: var(--clr-text);
}

.btn-secondary:hover {
  border-color: var(--clr-primary);
  background: var(--clr-active);
}

/* ---------- Folder Picker ---------- */
#folder-picker {
  background: var(--clr-surface);
  border: 2px dashed var(--clr-border);
  border-radius: var(--radius);
  padding: 2rem;
  text-align: center;
}

button {
  cursor: pointer;
  border: none;
  border-radius: var(--radius);
  font-size: 1rem;
  padding: 0.625rem 1.5rem;
  font-weight: 600;
  transition: background 0.15s;
}

#btn-pick-file,
#btn-pick-folder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-width: 140px;
}

#btn-pick-file {
  background: var(--clr-primary-fill);
  color: #fff;
  margin-right: 0.5rem;
}

#btn-pick-file:hover {
  background: var(--clr-primary-fill-hover);
}

#btn-pick-folder {
  background: var(--clr-primary-fill);
  color: #fff;
}

#btn-pick-folder:hover {
  background: var(--clr-primary-fill-hover);
}

#folder-path {
  font-size: 1.125rem;
  font-weight: 500;
}

/* Inline busy indicator, sized in em so it matches whatever text it sits beside.
   The shared CSS border ring: .pid-upload-spinner was a private copy of it and
   was migrated onto this in #3134.

   The two Data Viewer tree spinners are NOT copies of this and were wrongly
   described as such when this comment was first written. They are SVG arcs that
   swap in for a chevron inside a tree toggle — a different mechanism for a
   different job. They share one class with each other (.viewer-tree-spinner in
   data-viewer.css) and are deliberately not folded in here.

   .auth-submit-spinner still stands apart: same ring, but it shows via
   `.is-loading` on its parent rather than `.hidden` on itself, so it is not a
   drop-in. See .inline-spinner-on-fill below for the on-a-filled-button case. */
.inline-spinner {
  display: inline-block;
  flex: none;
  width: 1em;
  height: 1em;
  border: 2px solid var(--clr-border);
  border-top-color: var(--clr-primary);
  border-radius: 50%;
  animation: inline-spin 0.7s linear infinite;
}

@keyframes inline-spin {
  to { transform: rotate(360deg); }
}

/* On a filled button the palette pair is wrong: a --clr-primary ring on a
   primary fill is invisible. This borrows the button's own text colour instead,
   the same trick .auth-submit-spinner uses on the sign-in button (#2518). That
   one is not folded in here because it shows via `.is-loading` on its parent
   rather than `.hidden` on itself, so it is not a drop-in. */
.inline-spinner-on-fill {
  border-color: color-mix(in srgb, currentColor, transparent 65%);
  border-top-color: currentColor;
}

/* Respect a reduced-motion preference: the ring still reads as "busy" through
   its off-colour segment, it simply stops rotating. */
@media (prefers-reduced-motion: reduce) {
  .inline-spinner {
    animation: none;
  }
}

/* The button becomes a row so the ring sits beside its label rather than
   displacing it. */
#btn-validate {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.date-fmt-select {
  margin-top: 0.35rem;
  display: block;
}

.pg-col-input {
  width: 100%;
  min-width: 160px;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--clr-border);
  border-radius: 4px;
  font-size: 0.85rem;
  font-family: "Cascadia Code", "Consolas", monospace;
  background: var(--clr-input-bg);
  color: var(--clr-text);
}

.type-badge {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 4px;
  font-size: 0.8rem;
  font-weight: 600;
  background: var(--clr-surface-alt);
  color: var(--clr-muted);
}
.links-seg {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
  max-width: 100%;
  flex-wrap: wrap;
  font-family: "Cascadia Code", "Consolas", monospace;
  font-size: 0.8rem;
}
/* Editable segment = a clickable chip pill (matches .viewer-bk-chip), with a
   caret to signal it opens a dropdown (#2730). */
.links-seg-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 22ch;
  border: 1px solid color-mix(in srgb, var(--clr-primary), transparent 62%);
  border-radius: 999px;
  padding: 0.16rem 0.55rem;
  background: color-mix(in srgb, var(--clr-primary), transparent 90%);
  color: var(--clr-primary);
  font: inherit;
  cursor: pointer;
  overflow: hidden;
}
.links-seg-btn .t {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.links-seg-btn .car {
  flex: none;
  font-size: 0.6rem;
  opacity: 0.75;
}
.links-seg-btn:hover,
.links-seg-btn.open {
  background: color-mix(in srgb, var(--clr-primary), transparent 80%);
  border-color: color-mix(in srgb, var(--clr-primary), transparent 45%);
}
.links-seg-btn.empty {
  color: var(--clr-muted);
  border: 1px dashed var(--clr-border);
  background: transparent;
  font-family: "Segoe UI", system-ui, sans-serif;
  font-weight: 600;
  font-size: 0.76rem;
}
.links-seg-btn.empty:hover {
  color: var(--clr-primary);
  border-color: color-mix(in srgb, var(--clr-primary), transparent 45%);
  background: color-mix(in srgb, var(--clr-primary), transparent 88%);
}
/* Keep the "." with the column part so it never orphans on wrap. */
.links-seg-col {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
}
.links-seg-dot {
  color: var(--clr-muted);
  font-weight: 800;
}
.links-seg-chips {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* Popover — reuses the ETLSelect option look (.etl-select-option) for consistency. */
.links-seg-pop {
  position: fixed;
  z-index: 9999;
  width: 280px;
  max-width: calc(100vw - 20px);
  display: grid;
  gap: 6px;
  padding: 0.5rem;
  border: 1px solid color-mix(in srgb, var(--clr-primary), transparent 58%);
  border-radius: 12px;
  background: var(--clr-elevated);
  box-shadow: var(--clr-shadow);
}
.links-seg-pop-input {
  width: 100%;
  border: 1px solid var(--clr-border);
  border-radius: 8px;
  background: var(--clr-surface-alt);
  color: var(--clr-text);
  padding: 0.4rem 0.55rem;
  font-size: 0.82rem;
  outline: none;
}
.links-seg-pop-input:focus {
  border-color: var(--clr-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--clr-primary), transparent 84%);
}
.links-seg-pop-list {
  /* A plain scrolling block (like .etl-select-options). NOT a grid: a bounded-height
     grid compresses the overflow:hidden options and clips them to ~18px rows (#2732). */
  display: block;
  max-height: 230px;
  overflow-y: auto;
}
.links-seg-pop-list .etl-select-option + .etl-select-option,
.links-seg-pop-list .links-seg-pop-group + .etl-select-option {
  margin-top: 1px;
}
.links-seg-pop-group {
  font-size: 0.64rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--clr-muted);
  padding: 6px 8px 2px;
}
.links-seg-pop .etl-select-option.selected {
  color: var(--clr-primary);
}

#match-columns-list {
  max-width: 100%;
}

#match-columns-list label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 400;
  margin-bottom: 0.3rem;
}

/* ---------- Row Value Row ---------- */
#parent-column-row,
#parent-target-column-row {
  display: block;
  margin-bottom: 1rem;
}

#parent-column-row label,
#parent-target-column-row label {
  font-weight: 600;
  font-size: 0.9rem;
  display: block;
  margin-bottom: 0.5rem;
}

.categories-multiselect {
  border: 1px solid var(--clr-border);
  border-radius: 4px;
  padding: 0.75rem;
  background: var(--clr-input-bg);
  max-width: 600px;
}

.categories-help {
  font-size: 0.8rem;
  margin: 0;
}

/* ---------- Buttons ---------- */
.secondary {
  background: var(--clr-bg);
  color: var(--clr-text);
  border: 1px solid var(--clr-border);
}

.secondary:hover {
  background: var(--clr-surface-alt);
}

#btn-import {
  background: #16a34a;
  color: #fff;
}

#btn-import:hover {
  background: #15803d;
}

#btn-validate {
  background: var(--clr-primary-fill);
  color: #fff;
}

#btn-validate:hover {
  background: var(--clr-primary-fill-hover);
}

/* Disabled must LOOK disabled: it now waits for the impact preview (#3496), and a
   full-strength primary button that ignores clicks reads as broken. Same treatment
   as #btn-auth-submit:disabled. */
#btn-validate:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

#btn-validate:disabled:hover {
  background: var(--clr-primary-fill);
}

.status-success {
  background: var(--clr-success-bg);
  border: 1px solid var(--clr-success-border);
  color: var(--clr-success-text);
}

.status-error {
  background: var(--clr-error-bg);
  border: 1px solid var(--clr-error-border);
  color: var(--clr-error-text);
}

.status-warning {
  background: var(--clr-warning-bg);
  border: 1px solid var(--clr-warning-border);
  color: var(--clr-warning-text);
}

/* Shared name-entry modal (window.prompt replacement) — see js/shared/prompt-modal.js */
.etl-prompt-modal {
  position: fixed;
  inset: 0;
  /* Shared top-level dialog layer (ETLPrompt + ETLConfirm). Must sit ABOVE
     in-page modal layers that raise themselves over a backdrop — notably the
     data-viewer Filters panel, whose backdrop is z-index 4000 and lifted
     toggle/panel is 4001 (css/styles/data-viewer.css). Otherwise a confirm
     opened from inside such a panel (e.g. "Discard filter changes?") renders
     behind it and is unreachable. Kept below the 9999 toast/notification layer
     so transient toasts still overlay an open dialog. */
  z-index: 5000;
}

.etl-prompt-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.5);
}

.etl-prompt-modal-card {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(440px, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow: auto;
  border: 1px solid var(--clr-border);
  border-radius: 12px;
  background: var(--clr-elevated);
  box-shadow: var(--clr-shadow);
  padding: 1rem;
}

.etl-prompt-modal-card h3 {
  margin: 0 0 0.75rem;
  font-size: 1.05rem;
}

.etl-prompt-modal-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.45rem;
}

/* Recently deleted (#3454). The shared recycle bin: a stack of sections, each
   a settings-table of deleted rows. Scrolls internally so a long list never
   pushes the modal past the viewport. */
#deleted-items-modal-sections {
  display: grid;
  gap: 1rem;
  max-height: 22rem;
  overflow-y: auto;
}

.deleted-items-section h4 {
  margin: 0 0 0.35rem;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--clr-muted);
}

.etl-prompt-modal-body label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--clr-muted);
}

.etl-prompt-modal-body input {
  min-height: var(--control-h);
  padding: 0 0.6rem;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius);
  background: var(--clr-input-bg);
  color: var(--clr-text);
}

.etl-prompt-modal-error {
  margin: 0;
  font-size: 0.8rem;
  color: var(--clr-danger, #dc2626);
}

.etl-prompt-modal-actions {
  margin-top: 0.9rem;
  display: flex;
  justify-content: flex-end;
  gap: 0.55rem;
}

/* Inline text-style button (e.g. the relationship modal's "Advanced" toggle). */
.link-button {
  align-self: flex-start;
  background: none;
  border: none;
  padding: 0;
  color: var(--clr-primary);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
}
.link-button:hover {
  color: var(--clr-primary-hover);
  text-decoration: underline;
}

.etl-confirm-modal-message {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--clr-text);
  white-space: pre-line;
}