/* ChemTrust dashboard shell — the eudr-x shell (sidebar.css + the shell
 * parts of style.css / operator-react.css) ported verbatim to ct-* classes
 * with the navy palette from spec-shell §16. Geometry, clamps, z-indices and
 * transition timings are kept 1:1 with the eudr-x source.
 *
 * OWNED BY WP1. Later packages add their OWN files (states.css, topbar.css,
 * dashboard.css, …) — nobody else edits this one.
 *
 * z-index ladder (keep — spec-shell §15.11):
 *   topbar 40 · sidebar 50 · toggle tab 51 · global-search menu 60 ·
 *   user dropdown 200 · notification panel 2000 · lang menu 9999
 */

/* ═══════════════════════════════════════════════════════════════
   BACKGROUND — navy hero art directly on <body> with a navy fallback
   colour. eudr-x note (sidebar.css:831-848): the dashboards never scroll
   the body itself (.ct-main's child is the scroll host), so plain
   `background-attachment: scroll` is fine here and dodges the iOS Safari
   URL-bar bug that `fixed` triggers. The SAME image serves light and dark
   mode; dark mode "darkens" purely via translucent dark cards on top.
   ═══════════════════════════════════════════════════════════════ */
body.ct-shell-active {
  background-color: var(--canvas);
  background-image: var(--canvas-art);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-attachment: scroll;
}

/* ── Dashboard shell — horizontal layout (sidebar.css:22-50) ── */
.ct-shell {
  /* dvh tracks the visual viewport on iOS so the shell shrinks when the
     Safari URL bar slides in — no more white strip at the bottom. Fall
     back to vh on browsers that don't support dvh yet. */
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
}

/* ── Right column: topbar + main + footer ── */
.ct-right {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

/* ═══════════════════ SIDEBAR (sidebar.css:52-288) ═══════════════════ */
.ct-shell .ct-sidebar {
  width: var(--sidebar-width);
  background: var(--sidebar-bg);
  display: flex;
  flex-direction: column;
  /* The shell already owns the dvh height and this is one of its flex items —
     re-asserting `height/min-height: 100vh` here made the sidebar taller than
     its own parent on mobile (vh ignores the URL bar) and gave the aside a
     SECOND scrollbar nested inside the nav's own. One height, one scroll host:
     the aside clips, .ct-sidebar-sections below scrolls. */
  height: 100%;
  min-height: 0;
  overflow: hidden;
  transition: width 0.25s ease;
  z-index: 50;
  flex-shrink: 0;
}
.ct-shell .ct-sidebar.collapsed {
  width: var(--sidebar-collapsed-width);
}

/* Collapsed state: hide labels/badges/brand text/section text/logout text.
   eudr-x removes them from the DOM (React); the vanilla port hides them —
   `white-space: nowrap; overflow: hidden` below prevents wrap-flash during
   the width transition (spec-shell §1). */
.ct-sidebar.collapsed .ct-sidebar-label,
.ct-sidebar.collapsed .ct-sidebar-badge,
.ct-sidebar.collapsed .ct-sidebar-brand-text,
.ct-sidebar.collapsed .ct-sidebar-section-text,
.ct-sidebar.collapsed .ct-sidebar-logout span {
  display: none;
}

/* Sidebar brand */
.ct-sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  height: 52px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--sidebar-border);
  transition: justify-content 0.25s ease;
}
.ct-sidebar.collapsed .ct-sidebar-brand {
  justify-content: center;
  padding: 0;
}
.ct-sidebar-logo-link {
  display: inline-flex;
  perspective: 800px; /* the Y-spin below reads as 3-D (house rule) */
  flex-shrink: 0;
}
.ct-sidebar-logo {
  /* Was 64px inside a 60px row — the logo was taller than the row that holds
     it, so it overflowed the brand into the nav below and ate a third of a
     200px sidebar. 38px reads as a brand mark rather than a banner, keeps the
     Y-spin, and leaves room for "ChemTrust · Ops" on ONE line. */
  width: 38px;
  height: 38px;
  object-fit: contain;
  flex-shrink: 0;
  animation: ctSidebarLogoSpinY 20s linear infinite;
  animation-delay: 20s;
  transform-origin: center;
  transform-style: preserve-3d;
  backface-visibility: visible;
  will-change: transform;
  transition: width 0.25s ease, height 0.25s ease;
}
.ct-sidebar.collapsed .ct-sidebar-logo {
  width: 30px;
  height: 30px;
}
.ct-sidebar-brand-text {
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--sidebar-text-active);
  /* At the old 64px the logo left ~165px here and "ChemTrust · Ops" had to wrap
     to two lines to avoid being hard-clipped to "ChemTrust ·" (an ops console
     that named itself wrong). The 38px mark leaves enough room for it to sit on
     one line; the wrap allowance stays as the fallback for a longer suffix,
     since truncating the product name is not an option. */
  letter-spacing: 0.5px;
  /* Deliberately NOT uppercased: the product is written "ChemTrust", and
     `text-transform: uppercase` rendered the one place the name is always on
     screen as "CHEMTRUST". A brand's casing is part of its spelling. */
  line-height: 1.15;
  min-width: 0;
  overflow: hidden;
}

/* eudr-x navLogoSpinY (style.css:433-445) verbatim: one fast Y-spin every
   20s (the spin itself takes 0.9s = 4.5% of the cycle), first spin after a
   20s delay. Defined here under its own name because pages.css's
   ctLogoSpinY (portal/login brand, loaded later) is the simplified
   continuous variant and keyframe names are global. */
@keyframes ctSidebarLogoSpinY {
  0% {
    transform: rotateY(0deg);
  }
  4.5% {
    transform: rotateY(360deg);
  }
  100% {
    transform: rotateY(360deg);
  }
}

/* Nav sections wrapper — grows to fill sidebar, pushes logout to bottom.
   Deliberately BLOCK, not a flex column: as a flex column it shrank its own
   children whenever the nav was taller than the sidebar, so on any laptop-height
   window (≤~700px) every section label was squeezed 36px → 24px and the bottom
   half of its glyphs was sliced off, and the last item ("Submissions") was cut
   through the middle. Flex was crushing the nav instead of scrolling it. Block
   layout cannot crush a child, so the nav keeps its true height and this one
   element scrolls if it genuinely has to. */
.ct-sidebar-sections {
  flex: 1 1 auto;
  min-height: 0;
  display: block;
  overflow-y: auto;
  overflow-x: hidden;
  /* Don't chain the wheel to the page once the nav hits its end. */
  overscroll-behavior: contain;
  /* Reserve the gutter so appearing/disappearing scrollbars never shift labels. */
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: rgba(209, 223, 232, 0.28) transparent;
}
/* The default Chrome scrollbar is a light-grey slab with arrow buttons — on the
   deep-navy sidebar it read as a bright vertical stripe down the middle of the
   nav (and looked broken in dark mode). Thin, navy-tinted, no buttons. */
.ct-sidebar-sections::-webkit-scrollbar {
  width: 6px;
}
.ct-sidebar-sections::-webkit-scrollbar-track {
  background: transparent;
}
.ct-sidebar-sections::-webkit-scrollbar-thumb {
  background: rgba(209, 223, 232, 0.2);
  border-radius: 3px;
}
.ct-sidebar-sections::-webkit-scrollbar-thumb:hover {
  background: rgba(209, 223, 232, 0.36);
}
.ct-sidebar-sections::-webkit-scrollbar-button {
  display: none;
}

/* Section label (the div keeps its padding when collapsed — rhythm).
   line-height is explicit so the row's height is arithmetic, not whatever the
   font's default leading happens to be, and the label truncates rather than
   clipping mid-glyph if a translation runs long. */
.ct-sidebar-section {
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--sidebar-text);
  letter-spacing: 1px;
  text-transform: uppercase;
  padding: 13px 16px 5px;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ct-sidebar-section:first-of-type {
  padding-top: 10px;
}

/* Navigation items */
.ct-sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0;
}
.ct-sidebar-nav--grow {
  flex: 1;
}
/* The ungrouped first item (Dashboard) has no section label above it, so it
   needs the label's top breathing room itself. */
.ct-sidebar-nav--root {
  padding-top: 8px;
}

.ct-sidebar-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 16px;
  border-radius: 0;
  border: none;
  background: none;
  color: var(--sidebar-text);
  cursor: pointer;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  transition: all 0.15s ease;
  white-space: nowrap;
  overflow: hidden;
  text-align: left;
  width: 100%;
  text-decoration: none;
}
.ct-sidebar-item:hover {
  background: var(--sidebar-hover);
  color: var(--sidebar-text-active);
}
/* Active-state trick (eudr-x sidebar.css:619): no border — the "border"
   colour becomes the TEXT colour on the darker active background. Items are
   full-width, zero-radius, edge-to-edge. */
.ct-sidebar-item.active {
  background: var(--sidebar-active);
  color: var(--sidebar-active-border);
  font-weight: 600;
  /* "Where am I" is the one question a sidebar must answer at a glance. Tone
     alone did that weakly; the 2px rail is unmistakable. inset box-shadow, not
     a border, so the item's box never shifts by 2px when it becomes active. */
  box-shadow: inset 2px 0 0 var(--sidebar-active-border);
}
.ct-sidebar-item .ct-sidebar-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  opacity: 0.7;
}
.ct-sidebar-icon svg {
  width: 20px;
  height: 20px;
}
.ct-sidebar-item.active .ct-sidebar-icon {
  opacity: 1;
}
.ct-sidebar-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ct-sidebar-badge {
  margin-left: auto;
  background: #e67e22; /* status orange — kept as-is (eudr-x) */
  color: #fff;
  font-size: 0.6rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 8px;
  min-width: 16px;
  text-align: center;
  line-height: 1.4;
}

/* Step indicator (numbered circle for wizard steps) */
.ct-sidebar-step-num {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1.5px solid var(--sidebar-text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.65rem;
  font-weight: 700;
  flex-shrink: 0;
  transition: all 0.15s ease;
}
.ct-sidebar-item.active .ct-sidebar-step-num {
  border-color: var(--sidebar-active-border);
  background: var(--sidebar-active-border);
  color: #fff;
}
.ct-sidebar-item.completed .ct-sidebar-step-num {
  border-color: var(--sidebar-active-border);
  color: var(--sidebar-active-border);
}

/* Sidebar bottom (logout) — pinned at bottom via sidebar flex column */
.ct-sidebar-bottom {
  flex-shrink: 0;
  /* No inline padding here: it inset the logout row by 8px on top of its own
     12px, so the logout icon sat 4px right of every nav icon above it. The row
     owns its 16px inset like the nav items do, and the rule separates the
     destructive action from navigation. */
  padding: 6px 0 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-top: 1px solid var(--sidebar-border);
}
.ct-sidebar-logout {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  border-radius: 0;
  border: none;
  background: none;
  color: var(--sidebar-text);
  cursor: pointer;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  transition: all 0.15s ease;
  white-space: nowrap;
  width: 100%;
  text-align: left;
}
/* Match the 20px nav-icon box so the logout label lines up with every nav
   label above it instead of sitting 2px short. */
.ct-sidebar-logout svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  opacity: 0.7;
}
.ct-sidebar-logout:hover {
  background: rgba(231, 76, 60, 0.12);
  color: #e74c3c;
}
.ct-sidebar-logout:hover svg {
  opacity: 1;
}

/* Edge toggle — 3D tab hugging the sidebar's outer edge. `left` is driven
   inline by core/shell.js: calc(var(--sidebar-width) - 1px) expanded,
   calc(var(--sidebar-collapsed-width) - 1px) collapsed. */
.ct-sidebar-toggle {
  position: fixed;
  /* Vertically centred rather than pinned at 80px, where it landed exactly on
     the page-title row and butted against the first character of every heading
     and page description. Mid-height it never collides with content, and it is
     where a collapse handle is conventionally looked for. */
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 48px;
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 51;
  padding: 0;
  border-radius: 0 6px 6px 0;
  border: 1px solid var(--sidebar-border);
  border-left: none;
  box-shadow: 2px 0 6px rgba(0, 0, 0, 0.25);
  transition: left 0.25s ease, color 0.15s ease, background 0.15s ease;
}
.ct-sidebar-toggle:hover {
  background: var(--sidebar-hover);
  color: var(--sidebar-text-active);
}

/* ═══════════════════ TOPBAR (sidebar.css:290-373) ═══════════════════ */
.ct-topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 24px;
  background: var(--topbar-bg);
  flex-shrink: 0;
  height: 52px;
  position: sticky;
  top: 0;
  z-index: 40;
}
/* Small/medium laptops: tighter topbar so the dashboard content gets more
   vertical room. Mobile (≤768) is handled separately in mobile.css. */
@media (min-width: 769px) and (max-width: 1599px) {
  .ct-topbar {
    height: 46px;
    padding: 0 18px;
    gap: 10px;
  }
}
.ct-topbar-title {
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--sidebar-text-active);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 1;
  min-width: 0;
}
.ct-topbar-left {
  display: flex;
  align-items: center;
  gap: 6px;
}
.ct-topbar-center {
  flex: 1;
  display: flex;
  max-width: 400px;
}

/* The order trick (sidebar.css:333-346): DOM order is left→center→right
   (screen-reader friendly), but on desktop the icon cluster is visually
   moved next to the profile chip on the right. */
@media (min-width: 601px) {
  .ct-topbar-left {
    order: 2;
    margin-left: auto;
  }
  .ct-topbar-center {
    order: 1;
  }
  .ct-topbar-right {
    order: 3;
    margin-left: 0;
  }
}

.ct-topbar-right {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
}

/* Desktop override — the earlier @media block (next to .ct-topbar-left)
   lost to this .ct-topbar-right base rule because both have equal
   specificity and the base rule is defined later in the source. Repeat
   the `margin-left: 0` here so the icon group can claim the spare space
   and pack flush against the profile without a gap. (eudr-x documents this
   trap in sidebar.css itself — keep both blocks.) */
@media (min-width: 601px) {
  .ct-topbar-right {
    margin-left: 0;
  }
}

/* Icon buttons (sidebar.css:556-572) */
.ct-topbar-icon-btn {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  border: none;
  background: none;
  color: var(--sidebar-text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s;
}
.ct-topbar-icon-btn:hover {
  background: var(--sidebar-hover);
  color: var(--sidebar-text-active);
}

/* The existing flag lang-toggle (core/i18n.js renders flag + target-language
   label into [data-lang-toggle]) relocated into the icon cluster: widen the
   32px icon-button chrome to fit "🇬🇷 ΕΛ" while keeping its height/hover. */
.ct-topbar .ct-lang-toggle {
  width: auto;
  min-width: 32px;
  padding: 0 8px;
  border: none;
  background: none;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--sidebar-text);
}
.ct-topbar .ct-lang-toggle:hover {
  background: var(--sidebar-hover);
  color: var(--sidebar-text-active);
}

/* Theme toggle (inert until dark.css/theme.js — WP7 — land): light mode
   shows the outline moon; dark.css swaps in the filled sun. This base rule
   keeps the button single-icon meanwhile. */
#themeToggle .icon-sun {
  display: none;
}

/* Empty widget slots (WP4 fills them): reserve no space while empty. */
.ct-global-search:empty,
.ct-bell-container:empty {
  display: none;
}
.ct-bell-container {
  position: relative;
  display: flex;
  align-items: center;
}

/* ═══════════ USER AVATAR CHIP (sidebar.css:693-742 + style.css:457-499) ═══════════ */
.ct-topbar-user {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: 6px;
  padding-left: 10px;
  border-left: 1px solid var(--sidebar-border);
}
.ct-topbar-user-clickable {
  cursor: pointer;
  border-radius: 8px;
  padding: 4px 8px 4px 10px;
  transition: background 0.15s ease;
}
.ct-topbar-user-clickable:hover {
  background: var(--sidebar-hover);
}
.ct-topbar-user-clickable:focus-visible {
  outline: 2px solid var(--accent, #526878);
  outline-offset: 2px;
}
.ct-topbar-user .ct-header-avatar {
  width: 28px;
  height: 28px;
  font-size: 0.72rem;
}
.ct-topbar-user-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.2;
}
.ct-topbar-user-name {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--sidebar-text-active, var(--text, #0e1823));
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ct-topbar-user-email {
  font-size: 0.68rem;
  color: var(--sidebar-text, #8898aa);
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.75;
}
/* Tenant name · role separator (the middot only appears once session.js has
   filled the tenant span — gt staff have none). */
.ct-topbar-user-email [data-session-tenant]:not(:empty)::after {
  content: " · ";
}

/* --- HEADER AVATAR (gradient blue — deliberately blue even in the navy
   app, same as eudr-x kept it blue in the green app: brand accent pop,
   spec-shell §15.8) --- */
.ct-header-avatar {
  width: 35px;
  height: 35px;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: linear-gradient(135deg, #77abfa 0%, #2a5bb6 100%);
  box-shadow:
    0 3px 8px rgba(47, 111, 228, 0.45),
    inset 0 1px 2px rgba(255, 255, 255, 0.35);
  color: #ffffff;
  font-weight: 700;
  font-size: 14px;
  cursor: pointer;
  flex-shrink: 0;
  border: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.ct-header-avatar:hover {
  transform: translateY(-1px);
  box-shadow:
    0 5px 12px rgba(47, 111, 228, 0.55),
    inset 0 1px 2px rgba(255, 255, 255, 0.35);
}
body.dark-mode .ct-header-avatar {
  background: linear-gradient(135deg, #5d8dff 0%, #304aa0 100%);
}

/* ═══════════ DROPDOWN MENU (style.css:2486-2563; shared vocabulary for the
   user menu, bell panel chrome and future menus — WP4/WP7 reuse) ═══════════ */
.ct-dropdown-content {
  display: none;
  position: absolute;
  right: 0;
  top: 50px;
  background: linear-gradient(145deg, #ffffff 0%, #f6f8fb 100%);
  min-width: 240px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.18);
  border-radius: 14px;
  z-index: 200;
  border: 1px solid #e6edf5;
  padding: 10px 0;
  overflow: hidden;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.show-dropdown {
  display: block;
  animation: fadeIn 0.2s;
}
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.ct-dropdown-header {
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: linear-gradient(90deg, rgba(114, 148, 183, 0.08), rgba(37, 47, 69, 0.04));
}
.ct-dropdown-email {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--primary-color);
}
.ct-dropdown-subtext {
  font-size: 0.8rem;
  color: #7a8aa2;
  letter-spacing: 0.02em;
}
.ct-dropdown-divider {
  height: 1px;
  background: #e4ebf3;
  margin: 8px 14px;
}
.ct-dropdown-item {
  padding: 12px 16px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  color: var(--primary-color);
  align-items: center;
  gap: 12px;
  transition: background-color 0.18s ease, transform 0.18s ease;
}
.ct-dropdown-item:hover {
  background-color: #eef3f9;
  transform: translateY(-1px);
}
.ct-menu-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  color: var(--secondary-color);
  background: rgba(114, 148, 183, 0.15);
  border-radius: 8px;
}
.ct-menu-icon svg {
  width: 18px;
  height: 18px;
}

/* ═══════════════════ MAIN CONTENT (sidebar.css:755-770) ═══════════════════
   `overflow: hidden` is load-bearing: the main area itself never scrolls —
   its child is the scroll host. Full-bleed apart from the content-column cap
   below. Background is transparent so the body hero art shows through. */
.ct-shell .ct-main {
  flex: 1;
  min-width: 0;
  min-height: 0;
  /* 32px inline so content clears the 14px collapse tab riding the sidebar's
     edge; 20px left the first character of every title touching it. */
  padding: 20px 32px;
  display: flex;
  flex-direction: column;
  gap: 0;
  overflow: hidden;
  background: transparent;
}
@media (min-width: 769px) and (max-width: 1599px) {
  .ct-shell .ct-main {
    /* Asymmetric on purpose: the 14px collapse tab rides the sidebar edge, and
       at a symmetric 14px the tab landed flush against the first card's left
       border and read as a handle glued to the card rather than to the sidebar. */
    padding: 10px 16px 10px 26px;
  }
}

/* Cap and center every screen's content column for readable line lengths
   (moved here from app.css — single owner). Wrapped in :where() so this is
   a zero-specificity DEFAULT — a screen that needs another width overrides
   it with a plain class selector without a specificity fight. */
:where(.ct-main) > * {
  /* width:100% is load-bearing, not belt-and-braces. .ct-main is a COLUMN flex
     container, and an auto inline margin on a column flex item cancels the
     default cross-axis stretch — so each child shrank to its own content and
     centred itself independently. Every page then opened at a different left
     edge (a narrow findings table vs a wide SDS table), and the layout visibly
     jumped sideways on navigation. Pinning the width first, then centring the
     box, gives every page one shared column. */
  width: 100%;
  max-width: 1120px;
  /* Centred, not left-hugging. With margin-inline:0 the column stayed pinned
     left and every pixel gained by collapsing the sidebar turned into dead
     space on the right — collapsing appeared to do nothing but push the page
     off-centre. */
  margin-inline: auto;
}

/* Existing pages mount into #page-root: it becomes the scroll host so the
   body/shell never scroll (eudr-x rigid pattern, spec-shell §8.1). */
.ct-shell .ct-main > #page-root:not(.ct-card-rigid) {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
/* Pinned siblings (e.g. the ops #ops-switcher banner) never get squeezed.
   (:not(#page-root) carries ID specificity, so rigid cards are excluded
   explicitly or they would lose their flex-shrink.) */
.ct-shell .ct-main > :not(#page-root):not(.ct-card-rigid) {
  flex-shrink: 0;
}

/* Rigid card (operator-react.css:254-305): fills the remaining viewport,
   never scrolls itself — a pinned header row (flex-shrink:0) plus one inner
   scroll host (flex:1; min-height:0; overflow-y:auto) live inside it. */
.ct-shell .ct-main > .ct-card-rigid {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.ct-card-rigid > .ct-card-scroll {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

/* ═══════════════════ FOOTER (sidebar.css:772-798) ═══════════════════ */
.ct-bottom-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 0 24px;
  background: var(--topbar-bg);
  height: 36px;
  flex-shrink: 0;
  font-size: 0.72rem;
  color: var(--sidebar-text);
  flex-wrap: wrap;
  border-top: 1px solid var(--sidebar-border);
}
.ct-bottom-footer a {
  color: var(--sidebar-text);
  text-decoration: none;
  transition: color 0.15s ease;
}
.ct-bottom-footer a:hover {
  color: var(--sidebar-text-active);
}
.ct-bottom-footer-divider {
  color: rgba(209, 223, 232, 0.3);
  font-size: 0.6rem;
}

/* ═══════════ RESPONSIVE SHELL TIERS (sidebar.css:853-868) ═══════════
   ≤900px: JS auto-collapses the sidebar (core/shell.js matchMedia — width
   is owned by the JS class, NOT by CSS, or the toggle tab detaches from the
   sidebar edge, spec-shell §15.9). CSS only trims chrome here. */
@media (max-width: 900px) {
  /* The title is NOT hidden here any more. It used to be, back when it was
     unpopulated chrome; from 601px up the sidebar is auto-collapsed to icons, so
     this line is the only thing naming the current screen. (≤600px it does go
     away with the whole .ct-topbar-center — there the bottom nav names the
     screen.) It ellipsises rather than pushing the icon cluster around. */
  .ct-topbar-title {
    font-size: 0.88rem;
  }
  .ct-topbar-user-email {
    display: none;
  }
  .ct-shell .ct-main {
    padding: 16px 14px;
  }
}
@media (max-width: 600px) {
  .ct-shell .ct-sidebar {
    display: none;
  }
  .ct-sidebar-toggle {
    display: none;
  }
  .ct-topbar-center {
    display: none;
  }
  .ct-shell .ct-main {
    padding: 10px 8px;
  }
}

/* ═══════════ THEME CONTRACT (spec-theme §1.6 / spec-shell §2.3) ═══════════
   The sidebar/topbar chrome is deep navy in BOTH themes. Light mode
   re-asserts the exact same values (verbatim eudr-x pattern,
   sidebar.css:803-812) so dark.css's token flip can never lighten the
   chrome by accident. The body.dark-mode blocks below are no-ops until WP7
   adds the class toggle. */
body:not(.dark-mode) {
  --sidebar-bg: #0b1724;
  --sidebar-border: #122334;
  --sidebar-hover: #16293d;
  --sidebar-active: #1a3349;
  --sidebar-active-border: #a9bfd0;
  --sidebar-text: rgba(209, 223, 232, 0.78);
  --sidebar-text-active: #d1dfe8;
  --topbar-bg: #0b1724;
}

/* Dark mode: chrome intentionally identical (no flip) — re-asserted so a
   future dark.css rule can't drift the shell. */
body.dark-mode .ct-shell .ct-sidebar,
body.dark-mode .ct-sidebar-toggle {
  background: var(--sidebar-bg);
}
body.dark-mode .ct-topbar,
body.dark-mode .ct-bottom-footer {
  background: var(--topbar-bg);
}
body.dark-mode.ct-shell-active {
  background-color: #0e1c2b;
  background-image: url("/static/images/background.svg");
}

/* Dropdown vocabulary in dark mode (style.css:2891-2918, navy-substituted;
   inert until WP7). */
body.dark-mode .ct-dropdown-content {
  background: linear-gradient(145deg, rgba(16, 27, 42, 0.98) 0%, rgba(22, 36, 54, 0.94) 100%);
  border-color: var(--border-color);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
}
body.dark-mode .ct-dropdown-header {
  background: linear-gradient(90deg, rgba(82, 104, 120, 0.12), rgba(255, 255, 255, 0.02));
}
body.dark-mode .ct-dropdown-subtext {
  color: #a9c4d6;
}
body.dark-mode .ct-dropdown-divider {
  background: rgba(255, 255, 255, 0.08);
}
body.dark-mode .ct-dropdown-item:hover {
  background-color: rgba(82, 104, 120, 0.14);
}
body.dark-mode .ct-menu-icon {
  background: rgba(82, 104, 120, 0.22);
  color: var(--secondary-color);
}
