:root {
  /* Brand accent - active-manufacturer highlight, sidebar-toggle hover/
     focus, etc. `--brand-accent-rgb` is the same color as separate R,G,B
     components (no `#`), for use inside rgba(var(--brand-accent-rgb), A)
     wherever a translucent tint of the accent (not a solid color) is
     needed - keeping both in sync here means every accent usage in this
     file updates from one place. */
  --brand-accent: #879b3d;
  --brand-accent-rgb: 135, 155, 61;
  --brand-accent-hover: #728333;
  --brand-accent-active: #616f2b;

  /* Secondary brand color (the logo's orange) - used for the "warning /
     resume-style" button family so the two logo colors are the app's
     only accent colors, instead of Bootstrap's stock blue/yellow. */
  --brand-secondary: #ec8629;
  --brand-secondary-rgb: 236, 134, 41;
  --brand-secondary-hover: #c87122;
  --brand-secondary-active: #a9601d;
}

/* ---------------------------------------------------------------------
   Buttons - re-skin Bootstrap's primary/warning families with the
   logo's two colors (olive #879b3d, orange #ec8629) so every "main
   action" button in the app reads as this brand's, not stock Bootstrap
   blue/yellow. Outline variants get the same treatment (colored
   border/text at rest, solid fill on hover). A crisper border (1.5px,
   full color instead of Bootstrap's semi-transparent default) and a
   faint resting shadow give solid buttons a bit of lift instead of
   sitting flush with the page. */
.btn {
  border-width: 1.5px;
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease, color .15s ease;
}

.btn-primary {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
  color: #fff;
  box-shadow: 0 1px 2px rgba(var(--brand-accent-rgb), .35);
}
.btn-primary:hover,
.btn-primary:active,
.btn-check:checked + .btn-primary {
  background-color: var(--brand-accent-hover) !important;
  border-color: var(--brand-accent-hover) !important;
  color: #fff;
}
.btn-primary:focus,
.btn-primary:focus-visible {
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .35);
}
.btn-primary:active:focus {
  background-color: var(--brand-accent-active) !important;
  border-color: var(--brand-accent-active) !important;
}
.btn-primary:disabled,
.btn-primary.disabled {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
  box-shadow: none;
  opacity: .5;
}

.btn-outline-primary {
  color: var(--brand-accent);
  border-color: var(--brand-accent);
}
.btn-outline-primary:hover,
.btn-outline-primary:active,
.btn-outline-primary.active,
.btn-check:checked + .btn-outline-primary {
  background-color: var(--brand-accent) !important;
  border-color: var(--brand-accent) !important;
  color: #fff !important;
  box-shadow: 0 1px 2px rgba(var(--brand-accent-rgb), .35);
}
.btn-outline-primary:focus,
.btn-outline-primary:focus-visible {
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .25);
}

.btn-warning {
  background-color: var(--brand-secondary);
  border-color: var(--brand-secondary);
  color: #fff;
  box-shadow: 0 1px 2px rgba(var(--brand-secondary-rgb), .35);
}
.btn-warning:hover,
.btn-warning:active {
  background-color: var(--brand-secondary-hover) !important;
  border-color: var(--brand-secondary-hover) !important;
  color: #fff !important;
}
.btn-warning:focus,
.btn-warning:focus-visible {
  box-shadow: 0 0 0 .2rem rgba(var(--brand-secondary-rgb), .35);
}
.btn-warning:active:focus {
  background-color: var(--brand-secondary-active) !important;
  border-color: var(--brand-secondary-active) !important;
}
.btn-warning:disabled,
.btn-warning.disabled {
  background-color: var(--brand-secondary);
  border-color: var(--brand-secondary);
  box-shadow: none;
  opacity: .5;
}

.btn-outline-warning {
  color: var(--brand-secondary);
  border-color: var(--brand-secondary);
}
.btn-outline-warning:hover,
.btn-outline-warning:active,
.btn-outline-warning.active,
.btn-check:checked + .btn-outline-warning {
  background-color: var(--brand-secondary) !important;
  border-color: var(--brand-secondary) !important;
  color: #fff !important;
  box-shadow: 0 1px 2px rgba(var(--brand-secondary-rgb), .35);
}
.btn-outline-warning:focus,
.btn-outline-warning:focus-visible {
  box-shadow: 0 0 0 .2rem rgba(var(--brand-secondary-rgb), .25);
}

/* "All" category tab (.btn-outline-secondary) - Bootstrap's own default
   outline-secondary hover already fills to this same gray, but made
   explicit here (same pattern as -primary/-warning above, including the
   .btn-check:checked state their own re-skin needed) so this tab's
   hover/checked look can't silently drift from the region badges' own
   identical gray hover below if Bootstrap's own defaults ever change. */
.btn-outline-secondary:hover,
.btn-outline-secondary:active,
.btn-outline-secondary.active,
.btn-check:checked + .btn-outline-secondary {
  background-color: #6c757d !important;
  border-color: #6c757d !important;
  color: #fff !important;
}

/* Modules list's own "Sync details" modal - the Siemens "All Countries
   (Live REST Listing)" region badges, tinted to match whichever
   document-types= category button (.btn-outline-primary/-warning, both
   already re-skinned to the brand's own two colors above) is currently
   selected - see modules_list.html's own SIEMENS_COUNTRY_CATEGORY_
   BADGE_CLASS. Bootstrap has no built-in "subtle" background for these
   two custom brand colors (unlike its own bg-info-subtle/bg-success-
   subtle), so this hand-builds the same light-tint-background/solid-
   text-color pairing from the brand RGB vars instead of introducing a
   third, unrelated color. */
.msd-country-badge-accent,
.msd-country-badge-secondary {
  transition: background-color .15s ease, color .15s ease;
}
.msd-country-badge-accent {
  background-color: rgba(var(--brand-accent-rgb), .15);
  color: var(--brand-accent-hover);
}
.msd-country-badge-accent:hover {
  background-color: var(--brand-accent) !important;
  color: #fff !important;
}
.msd-country-badge-secondary {
  background-color: rgba(var(--brand-secondary-rgb), .15);
  color: var(--brand-secondary-hover);
}
.msd-country-badge-secondary:hover {
  background-color: var(--brand-secondary) !important;
  color: #fff !important;
}
/* "All" category badges use Bootstrap's own plain bg-secondary-subtle
   (no custom class - see SIEMENS_COUNTRY_CATEGORY_BADGE_CLASS) - scoped
   to this list specifically so this hover doesn't change every OTHER
   bg-secondary-subtle badge/pill elsewhere on this page. */
#msd-siemens-country-links-list a.bg-secondary-subtle {
  transition: background-color .15s ease, color .15s ease;
}
#msd-siemens-country-links-list a.bg-secondary-subtle:hover {
  background-color: #6c757d !important;
  color: #fff !important;
}

/* Tighter than Bootstrap's own gap-3 (1rem) utility this box used to
   carry - ~50+ region badges wrapping across several lines read better
   snug than with a full-rem gap between every one. */
#msd-siemens-country-links-list {
  gap: 0.3rem !important;
}

/* Secondary/neutral buttons ("Cancel", "Edit", "Clear filters", "Pause",
   etc.) deliberately stay gray rather than picking up either brand color
   - they're not the primary action on their page and using olive/orange
   here would blur the distinction from real primary/warning actions. But
   they get the same crisper-border + hover-fill + shadow treatment as
   the brand-colored buttons above, instead of Bootstrap's flatter,
   lighter-gray default, so the whole button set reads as one consistent
   family. */
.btn-secondary {
  background-color: #6c757d;
  border-color: #6c757d;
  color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.btn-secondary:hover,
.btn-secondary:active {
  background-color: #565e64 !important;
  border-color: #565e64 !important;
  color: #fff !important;
}
.btn-secondary:focus,
.btn-secondary:focus-visible {
  box-shadow: 0 0 0 .2rem rgba(108, 117, 125, .35);
}
.btn-secondary:disabled,
.btn-secondary.disabled {
  background-color: #6c757d;
  border-color: #6c757d;
  box-shadow: none;
  opacity: .5;
}

.btn-outline-secondary {
  color: #495057;
  border-color: #adb5bd;
}
.btn-outline-secondary:hover,
.btn-outline-secondary:active {
  background-color: #495057 !important;
  border-color: #495057 !important;
  color: #fff !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.btn-outline-secondary:focus,
.btn-outline-secondary:focus-visible {
  box-shadow: 0 0 0 .2rem rgba(73, 80, 87, .2);
}

/* overflow-x:hidden on the ROOT element only (not body) - confirmed
   live this matters: with it on BOTH html and body, Chromium's real
   `position: sticky` implementation treated body itself as a scroll
   container (its computed overflow isn't "visible", so it's a
   candidate ancestor for sticky's containing-block search) even though
   body's own scrollTop never actually moves (the real page scroll
   happens via document.documentElement/window instead) - so anything
   sticky ended up scoped to stick within body's own (never-scrolling)
   box, and just scrolled away with the rest of the page instead of
   sticking at all (confirmed live: .sticky-action-bar's own
   getBoundingClientRect().top went to -816px after a 900px scroll,
   instead of clamping at its `top: 60px`). Root-only avoids this: the
   CSS Overflow spec's "root element's overflow propagates to the
   viewport instead of creating its own scroll box" exemption applies
   cleanly with a single, unambiguous owner (html), with no separate
   non-visible overflow on body to also compete for that role. */
html {
  overflow-x: hidden;
  max-width: 100%;
}

body {
  background-color: #f4f6f9;
  max-width: 100%;
}

#app-shell {
  min-height: 100vh;
  max-width: 100%;
}

/* Bootstrap's .bg-primary utility (badges, progress bars, etc.) - brand
   olive instead of stock Bootstrap blue, matching the .btn-primary
   re-skin above. !important to beat Bootstrap's own --bs-bg-opacity-
   based background-color, same as Bootstrap's own utility does to
   itself. */
.bg-primary {
  --bs-bg-opacity: 1;
  background-color: rgba(var(--brand-accent-rgb), var(--bs-bg-opacity)) !important;
}

/* Job progress bars (Analyze/Download Documents/Sync to Drive, all
   sharing the same striped-animated "still working" look) - brand
   orange fill with olive-tinted stripes instead of Bootstrap's plain
   blue + white-stripe default, so the "loader" itself reads as this
   app's own rather than a stock Bootstrap component. Only touches the
   bare, no-status-yet state - a finished bar gets bg-success/bg-danger/
   etc. instead (untouched, so terminal colors still read normally). */
.progress-bar {
  background-color: var(--brand-accent);
}

/* Modules list's own "Sync details" modal - the per-module success-rate
   bar/text (#msd-rate-wrap, modules_list.html) only, NOT Bootstrap's
   .progress-bar/.text-success everywhere else in the app (those keep
   their own real green/red meaning - a job's own progress bar above,
   a document's own success/fail count elsewhere, etc.) - scoped to this
   one wrapper so re-skinning this specific success/fail bar to the
   brand's two colors can't bleed into any of that. */
#msd-rate-wrap .progress-bar.bg-success {
  background-color: var(--brand-accent) !important;
}
#msd-rate-wrap .text-success {
  color: var(--brand-secondary) !important;
}

/* Fixed (not content-sized) height so any page's own sticky action bar
   (see .sticky-action-bar below) can stick at a known, exact offset
   right below it, instead of guessing at whatever height the navbar-
   text/dropdown button happen to size it to. Bootstrap's own
   .sticky-top utility (added in base.html) handles keeping this pinned
   to the very top of the viewport as the page scrolls. */
.navbar {
  height: 60px;
  z-index: 1020;
  border-bottom-color: #eceff2 !important;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .04);
}

.navbar .navbar-text {
  font-size: 1.05rem;
  color: #212529;
  letter-spacing: -.01em;
}

/* Top-right user menu - a rounded "chip" (avatar initial + name) instead
   of a plain outline button with a stock person icon, so it reads as a
   modern account switcher rather than a generic Bootstrap dropdown. */
.user-menu-btn {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  border: 1px solid #e9ecef;
  background-color: #fff;
  border-radius: 2rem;
  padding: .3rem .9rem .3rem .3rem;
  color: #343a40;
  font-weight: 600;
  font-size: .9rem;
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.user-menu-btn:hover,
.user-menu-btn:focus,
.user-menu-btn:active,
.user-menu-btn.show {
  background-color: #f8f9fb !important;
  border-color: var(--brand-accent) !important;
  color: #343a40 !important;
  box-shadow: 0 0 0 .15rem rgba(var(--brand-accent-rgb), .12);
}
.user-menu-btn::after {
  opacity: .45;
  margin-left: .1rem;
}
.user-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.85rem;
  height: 1.85rem;
  flex-shrink: 0;
  border-radius: 50%;
  background-image: linear-gradient(135deg, var(--brand-accent), var(--brand-secondary));
  color: #fff;
  font-size: .8rem;
  font-weight: 700;
}

/* The dropdown menu itself - a real floating card (soft shadow, no hard
   border, rounded items with a brand-tinted hover) instead of Bootstrap's
   flat 1px-bordered default. */
.user-dropdown-menu {
  border: none;
  border-radius: .65rem;
  box-shadow: 0 12px 28px rgba(0, 0, 0, .12), 0 2px 6px rgba(0, 0, 0, .06);
  padding: .4rem;
  min-width: 12rem;
}
.user-dropdown-menu .dropdown-item {
  display: flex;
  align-items: center;
  border-radius: .45rem;
  padding: .5rem .7rem;
  font-size: .9rem;
  transition: background-color .12s ease, color .12s ease;
}
.user-dropdown-menu .dropdown-item:hover,
.user-dropdown-menu .dropdown-item:focus {
  background-color: rgba(var(--brand-accent-rgb), .1);
  color: #212529;
}
.user-dropdown-menu .dropdown-item.text-danger:hover,
.user-dropdown-menu .dropdown-item.text-danger:focus {
  background-color: rgba(220, 53, 69, .1);
  color: #dc3545;
}
.user-dropdown-menu .dropdown-divider {
  margin: .35rem 0;
}

/* A page's own title/action-buttons row, stuck right below the sticky
   top navbar (60px) - so checking checkboxes down a long table (e.g.
   Modules/Documents) still leaves "Download Documents"/"Sync to Google
   Drive" etc. reachable without scrolling back up first. `bg-body`
   (not transparent) so table rows scrolling underneath don't show
   through while it's stuck, and a bit of padding + a bottom border
   stand in for the card's own edge once this row visually detaches
   from the content that continues to scroll beneath it. */
.sticky-action-bar {
  position: sticky;
  top: 60px;
  z-index: 1015;
  background-color: #f4f6f9;
  padding-top: .5rem;
  padding-bottom: .75rem;
  transition: box-shadow .15s ease;
}

/* Only while actually stuck (JS toggles this via an IntersectionObserver
   in app.js) - a hairline shadow reads as "this detached from the page
   and is now floating above the content below it", instead of an
   unstyled bar that's ambiguous about whether it's part of the normal
   page flow or not. */
.sticky-action-bar.is-stuck {
  box-shadow: 0 4px 6px -4px rgba(0, 0, 0, 0.15);
}

/* analyze.html's own action bar (.analyze-header/.analyze-actions) - up
   to 7 buttons plus the "Last analyzed" label, too many to always fit
   one line next to the page's own <h4> at normal widths. Each button
   used to rely on a plain `ms-1` for spacing, which only ever pushes
   its LEFT side away from whatever precedes it on the SAME line - once
   .analyze-actions wraps to a second/third line, the wrapped row had no
   top spacing at all and sat flush against the row above it. `gap` (not
   per-button margin) puts real space BETWEEN every button in every
   direction, wrapped rows included, and between .analyze-actions itself
   and the <h4> once THAT wraps too (see flex-wrap on .analyze-header). */
.analyze-header {
  row-gap: .5rem;
}

.analyze-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
}

/* "Recheck Classification Sheets" (.analyze-actions) sat right next to
   "Download Classification Sheets" as the exact same btn-outline-
   secondary, muted-grey style - easy to mistake for one another at a
   glance despite doing very different things (one downloads, the other
   live-corrects stale Drive records). btn-outline-warning already gets
   re-skinned to the brand's own orange (--brand-secondary, see this
   file's own :root block) with a matching hover-fill, so this reuses
   that class rather than hardcoding #ec8629 again - just adds a small
   icon spin on hover on top, since bi-arrow-repeat already reads as a
   refresh/recheck action and the motion reinforces that without adding
   any extra visual weight. */
.recheck-classification-btn i.bi-arrow-repeat {
  display: inline-block;
  transition: transform .3s ease;
}

.recheck-classification-btn:hover i.bi-arrow-repeat {
  transform: rotate(180deg);
}

/* The main content column is a flex item; without min-width:0 a flex
   item's minimum width defaults to its content's intrinsic width (e.g.
   a long unwrapped log line, or a wide table), which forces the whole
   page wider than the viewport and causes horizontal scrolling. This
   forces it to actually shrink to the available space instead, so wide
   content scrolls locally (inside its own overflow:auto container)
   rather than the whole page scrolling sideways. */
#app-shell > .flex-grow-1 {
  min-width: 0;
  max-width: 100%;
}

main {
  min-width: 0;
  max-width: 100%;
  /* NOT overflow-x: hidden here (used to be) - a non-"visible" overflow
     on EITHER axis makes an element a scroll container for position:
     sticky purposes, even when nothing inside it actually overflows it
     (confirmed live: main's own height always matches its content's, so
     it never actually scrolls internally - but its sticky descendants,
     e.g. .sticky-action-bar, still got scoped to stick within main's
     own inert box instead of the real page/viewport scroll, so they
     just scrolled away with everything else instead of sticking at
     all). html/body's own overflow-x:hidden above already guards
     against whole-page horizontal scroll (the root element's overflow
     propagates to the viewport instead of creating its own scroll box -
     a different rule that doesn't apply to main, a non-root element) -
     and every genuinely wide piece of content already contains its own
     horizontal scroll independently anyway (.table-responsive, #job-log's
     own overflow:auto), so this was belt-and-suspenders, not load-bearing. */
}

#job-log {
  white-space: pre-wrap;
  word-break: break-word;
}

.sidebar {
  width: 260px;
  min-width: 260px;
  min-height: 100vh;
  /* flex column (not the default block stacking) so .sidebar-footer's
     mt-auto below can pin it to the very bottom of the sidebar even
     when the manufacturer/integrations lists above don't fill the
     viewport - a plain block layout would leave it wherever the
     content happened to end instead. Still stacks every existing child
     top-to-bottom exactly as before (flex-direction: column does the
     same thing block layout already did), and still grows past 100vh
     (scrolling the whole sidebar) for a tall manufacturer list, same as
     before - min-height, not height. */
  display: flex;
  flex-direction: column;
}

/* Deliberately understated, unlike every other sidebar link (which pairs
   an icon with a visible label) - a single small icon, faded to near-
   invisible until hovered, tucked at the very bottom below Integrations.
   Not meant to compete for attention with real navigation; still fully
   reachable (title tooltip + normal link semantics), just low-profile. */
.sidebar-footer {
  margin-top: auto;
  padding: .5rem;
  border-top: 1px solid rgba(255,255,255,.08);
  text-align: center;
}

.sidebar-footer .docs-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  color: rgba(255,255,255,.25);
  transition: color .15s ease, background-color .15s ease;
}

.sidebar-footer .docs-link:hover,
.sidebar-footer .docs-link:focus {
  color: rgba(255,255,255,.85);
  background-color: rgba(255,255,255,.08);
}

/* "Manage manufacturers" gear link next to the Manufacturers header -
   sits at 50% white (text-white-50) normally; needs !important to win
   on hover since Bootstrap's text-white-50 utility is ALSO !important
   (a plain, non-important hover rule would never override it). */
.sidebar .manage-manufacturers-link:hover {
  color: #fff !important;
}

.sidebar .nav-link {
  /* .5rem left/right - matches the sidebar-header/Manufacturers-toolbar/
     Integrations label rows above (all px-2), so a manufacturer's icon
     and every section header's text/icon start at the exact same left
     edge. Tightened from an earlier 1rem/px-3 - that lined everything up
     but left a noticeably wide, mostly-empty left margin the full
     height of the sidebar. */
  padding: .5rem .5rem;
}

.sidebar .nav-link.active-sublink {
  background-color: rgba(255,255,255,0.15);
  color: #fff !important;
  font-weight: 600;
}

/* The active manufacturer's own top-level row - color/background only,
   deliberately NOT font-weight (confirmed live: bolding widened a long
   name like "Siemens Healthineers" just enough to wrap onto a second
   line in the sidebar's fixed width - a plain color highlight reads as
   "selected" just as clearly without that risk). Applied to the whole
   `.manufacturer-row` (the flex div wrapping both the link AND its
   expand/collapse chevron button), not just the link's own box, so the
   highlight covers the full row edge-to-edge instead of stopping short
   wherever the link's flex-grow-1 box happens to end. The nav-link's
   own color still needs its own (!important) override here - Bootstrap's
   `text-white` utility on that link is ALSO `!important`, so only a
   more specific !important rule can beat it; a plain (non-important)
   color on the row wouldn't cascade down over that. */
.sidebar .manufacturer-row.active-manufacturer {
  background-color: rgba(255,255,255,0.1);
  border-radius: .25rem;
}

.sidebar .manufacturer-row.active-manufacturer .nav-link {
  color: var(--brand-accent) !important;
}

/* Light hover highlight for the whole row (link + chevron button
   together), same idea as .active-manufacturer's own background but
   subtler - removing the earlier blanket ".nav-link:hover" rule left
   this row with no hover feedback at all. */
.sidebar .manufacturer-row:hover {
  background-color: rgba(255, 255, 255, 0.06);
  border-radius: .25rem;
}

/* Slim vertical guide line ties each submenu item visibly back to its
   parent manufacturer row, the way a file-tree does. */
.sidebar .submenu-list {
  margin-left: .65rem;
  border-left: 2px solid rgba(255, 255, 255, 0.12);
}

.sidebar .submenu-list .nav-link {
  padding: .35rem .5rem;
  font-size: .85rem;
  color: rgba(255, 255, 255, 0.65);
}

.sidebar .submenu-list .nav-link i {
  font-size: .8rem;
  width: 1rem;
  text-align: center;
}

.sidebar .submenu-list .nav-link:hover {
  color: #fff;
}

.sidebar .submenu-list .nav-link.active-sublink {
  padding-left: calc(.5rem - 2px);
}

.manufacturer-row .toggle-sub {
  border: none;
  background: transparent;
  color: #adb5bd;
}

.manufacturer-row .toggle-sub:hover {
  color: #fff;
}

@media (max-width: 991.98px) {
  .sidebar {
    position: fixed;
    z-index: 1030;
    transform: translateX(-100%);
    transition: transform .2s ease-in-out;
  }
  .sidebar.show {
    transform: translateX(0);
  }
}

/* ---------------------------------------------------------------------
   Mini/icon-only sidebar (desktop) - toggled by #sidebar-collapse-toggle
   in base.html, state kept in the `sidebar_collapsed` cookie so it's
   restored (server-side, no flash) on every page load. Independent of
   the small-screen slide-in `.show` class above - this is a width
   change, not a show/hide.
   --------------------------------------------------------------------- */
.sidebar {
  transition: width .2s ease, min-width .2s ease;
}

.sidebar-mini-text {
  display: none;
}

/* Optional operator logo (app/__init__.py's /logo.png route, from a
   root-level logo.png - see base.html's `logo_exists` check) - a fixed
   square size regardless of the source image's own dimensions, so an
   arbitrarily-sized drop-in file never blows out the header's height or
   looks stretched. Stays visible in BOTH expanded and collapsed sidebar
   states (unlike the "DA" text it replaces, which only ever showed in
   one or the other) - a small brand mark reads fine at either width. */
.sidebar-logo {
  height: 28px;
  width: 28px;
  object-fit: contain;
  border-radius: 4px;
  flex-shrink: 0;
}

/* The logo/"Doc Admin" title is now a link to the Dashboard - a light
   hover highlight signals that, same idea as .manufacturer-row:hover
   below it in the sidebar. */
.sidebar-brand:hover {
  background-color: rgba(255, 255, 255, 0.08);
  border-radius: .25rem;
}

.sidebar.sidebar-collapsed {
  width: 72px;
  min-width: 72px;
}

.sidebar.sidebar-collapsed .sidebar-full-text,
.sidebar.sidebar-collapsed .sidebar-label {
  display: none;
}

.sidebar.sidebar-collapsed .sidebar-mini-text {
  display: inline-block;
}

/* Center icons (+ the manufacturer 2-letter short name) in the narrow
   rail instead of leaving them left-aligned in now-mostly-empty rows -
   `.manufacturer-row`'s own expand/collapse chevron button is hidden
   entirely (sidebar-label), so the manufacturer link itself just needs
   centering, same as every other icon-only nav-link. The header keeps
   its own small gap (rather than justify-content:between's now-huge gap
   with only "DA" + the toggle button left in it) between the shortened
   title and the toggle button. */
.sidebar.sidebar-collapsed .nav-link {
  justify-content: center;
  text-align: center;
  padding-left: .5rem;
  padding-right: .5rem;
}

.sidebar.sidebar-collapsed .sidebar-header,
.sidebar.sidebar-collapsed .manufacturers-toolbar {
  justify-content: center !important;
  gap: .5rem;
  padding-left: .5rem;
  padding-right: .5rem;
}

.sidebar.sidebar-collapsed .nav-link i {
  margin-right: 0 !important;
}

.sidebar.sidebar-collapsed .manufacturer-row {
  justify-content: center;
}

/* Submenus lose their left indent/guide line once there's no label text
   left to indent (a vertical LEFT line makes no sense once everything's
   centered) - replaced with a thin horizontal separator instead, so a
   manufacturer's icon-only children still read as "a group nested under
   the icon above", not just more centered icons in the same list. Sub-
   icons are also shrunk a step smaller than their parent - depth-by-size
   being the one hierarchy cue that still works with zero indentation
   room in a 72px rail. */
.sidebar.sidebar-collapsed .submenu-list {
  margin-left: 0 !important;
  padding-left: 0 !important;
  border-left: none !important;
  margin-top: .25rem;
  padding-top: .4rem;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.sidebar.sidebar-collapsed .submenu-list .nav-link i {
  font-size: .7rem;
}

/* The toggle button itself - a circular hit target around the
   fa-circle-chevron-* icon (which already reads as a button, this just
   gives it a real click/hover affordance instead of a bare icon
   floating in the header). */
.btn-sidebar-toggle {
  background: transparent;
  border: none;
  color: #adb5bd;
  font-size: 1.35rem;
  line-height: 1;
  padding: .25rem;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color .15s ease, background-color .15s ease, transform .15s ease;
}

.btn-sidebar-toggle:hover {
  color: var(--brand-accent);
  background-color: rgba(var(--brand-accent-rgb), 0.15);
  transform: scale(1.12);
}

.btn-sidebar-toggle:active {
  transform: scale(0.94);
}

.btn-sidebar-toggle:focus-visible {
  outline: 2px solid var(--brand-accent);
  outline-offset: 2px;
}

table.dataTable tbody tr {
  cursor: pointer;
}

/* Any wide table scrolls within its own card instead of the page */
.table-responsive {
  overflow-x: auto;
}

/* Long document/module title table cell (see documents_list.html's
   wrappingCell()) - wraps onto additional lines within a capped column
   width instead of running the column arbitrarily wide OR trimming the
   text with an ellipsis; the full title is always fully visible, just
   broken across lines rather than on one unbounded line. */
.dt-wrap-cell {
  display: inline-block;
  max-width: 320px;
  white-space: normal;
  word-break: break-word;
}

/* Small inline "external link" icons sitting right next to a title
   (Modules page - manufacturer site / Google Drive folder). Each gets
   its own distinct, muted accent rather than sharing one color or
   inheriting a link's default blue - lets the eye tell "this opens the
   manufacturer's site" apart from "this opens Drive" at a glance,
   without either one shouting for attention next to plain title text.
   Chosen a step lighter on hover, same easing as .btn-sidebar-toggle's
   own hover treatment elsewhere in this file, so both feel like part of
   the same interactive language rather than a one-off. */
.icon-link-site,
.icon-link-drive {
  transition: opacity 0.15s ease;
}

.icon-link-site {
  color: #0e7c86; /* muted teal - "this module's own page elsewhere on the web" */
}

.icon-link-drive {
  color: #4285F4; /* Google's own blue - immediately reads as "Drive", and distinct from --brand-accent's olive so it never looks like an app-native action */
}

.icon-link-analyze {
  color: #6c757d; /* Bootstrap's own neutral gray - plain and unobtrusive next to the manufacturer name, rather than competing with it like the brighter teal/Drive-blue icons above */
  transition: opacity 0.15s ease;
}

.icon-link-site:hover,
.icon-link-drive:hover,
.icon-link-analyze:hover {
  opacity: 0.7;
}

/* Marks the Drive-folder icon as pointing at a folder this module
   SHARES with another module (see modules_list.html's
   drive_folder_shared_with / api_modules()'s own docstring on it) - a
   step more muted than a dedicated one-to-one folder link so it doesn't
   visually read identically to one; the full explanation lives in its
   title tooltip. */
.icon-link-drive-shared {
  opacity: 0.6;
}

/* "i" hint icon next to the Modules table's "Success" column HEADER
   (see modules_list.html's <thead>) - explains, once, that a row's
   Success value is itself clickable for a full breakdown, rather than
   repeating an icon on every single row. Given its own recognizable
   "info" blue (not `color: inherit`) so it visibly stands apart from
   the plain header text instead of blending in - the whole point is to
   catch the eye as "hover/click me", which an icon the same color as
   its surrounding text fails to do. `cursor: help` is the same signal
   browsers already give native title-tooltip text, reinforcing that
   hovering it does something. Darkens slightly on hover/focus as
   feedback that it registered the pointer. */
.icon-info-hint {
  font-size: .95rem;
  vertical-align: -1px;
  color: #4a90d9;
  cursor: help;
  transition: color 0.15s ease;
}

.icon-info-hint:hover,
.icon-info-hint:focus {
  color: #2f6fb0;
}

/* .module-sync-status-highlight (see modules_list.html) is toggled on
   every visible row's Success cell in sync with the header info icon's
   tooltip (show.bs.tooltip/hide.bs.tooltip, not raw mouseenter/leave) -
   but deliberately carries NO styling of its own (no background, no
   box-shadow/border) on .module-sync-status itself. It exists purely as
   a state hook for .click-hint-pointer below - the hand icon fading in
   is the entire "click here" affordance, nothing about the
   check/x-icon-and-badge box itself changes. */

/* Hand-pointer hint sitting to the RIGHT of the Success column's check/x
   icon (see modules_list.html), pointing back at it - the 👈 emoji
   itself (plain text content, not an icon-font glyph), which already
   renders as a left-pointing hand in its own full color, no icon
   library or transform needed at all. `width` (not max-width) is a
   FIXED, constant value here, in both states - this reserves the same
   layout space always, so fading it in/out never shifts the check/x
   icon or anything else next to it. Only `opacity` actually animates.
   No `color` here - emoji render in their own fixed colors regardless
   of CSS color, unlike the icon-font glyphs used elsewhere on this
   page. */
.click-hint-pointer {
  display: inline-block;
  width: 1em;
  margin-left: .25rem;
  font-size: .8rem;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.module-sync-status-highlight .click-hint-pointer {
  opacity: 1;
}

/* Custom Bootstrap Tooltip skin ("app-tooltip", passed as `customClass`
   at init - see modules_list.html's initComplete) instead of Bootstrap's
   plain black default, which reads as generic/unbranded. A light card
   with a real shadow instead - shown with 0ms show/hide delay (set at
   init) and auto-repositioned by Popper (Bootstrap Tooltip's own
   dependency, already loaded via bootstrap.bundle.min.js) to whichever
   side of the viewport actually has room, so it's never clipped
   off-screen regardless of where the trigger icon sits.
   `[data-popper-placement^="..."]` (not Bootstrap's own .bs-tooltip-*
   placement classes, which vary in naming between versions and flip to
   logical start/end in RTL) is what Popper itself always stamps onto
   the tooltip element, so the arrow's color reliably matches whichever
   side it actually landed on. */
.tooltip.app-tooltip .tooltip-inner {
  background: #fff;
  color: #2b2f26;
  text-align: left;
  max-width: 260px;
  padding: .5rem .75rem;
  font-size: .8125rem;
  font-weight: 400;
  border-radius: .375rem;
  box-shadow: 0 .5rem 1.25rem rgba(0, 0, 0, .18);
}

.tooltip.app-tooltip[data-popper-placement^="top"] .tooltip-arrow::before {
  border-top-color: #fff;
}

.tooltip.app-tooltip[data-popper-placement^="bottom"] .tooltip-arrow::before {
  border-bottom-color: #fff;
}

.tooltip.app-tooltip[data-popper-placement^="left"] .tooltip-arrow::before {
  border-left-color: #fff;
}

.tooltip.app-tooltip[data-popper-placement^="right"] .tooltip-arrow::before {
  border-right-color: #fff;
}

/* Dashboard stat tiles - a subtle hover lift ties the whole row of cards
   together as one "at a glance" set, rather than reading as a plain grid
   of otherwise-identical boxes. */
.stat-card {
  border: 1px solid rgba(0, 0, 0, .08);
  transition: box-shadow .15s ease, transform .15s ease;
}

.stat-card:hover {
  box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .08);
  transform: translateY(-2px);
}

/* Dashboard "By manufacturer" table's count pills (see dashboard.html's
   count_pill() macro) - a fixed min-width so a column of single- and
   multi-digit counts still lines up cleanly instead of each pill hugging
   its own number's width. */
.count-pill {
  min-width: 2.5rem;
  display: inline-block;
  font-weight: 600;
}

a.count-pill:hover {
  filter: brightness(0.92);
}

/* ---------------------------------------------------------------------
   App-wide "modern table" theme - every table in the app, DataTables-
   backed (Modules, Documents, Fetch Modules, the Individual Module page,
   etc.) or a plain Bootstrap `.table` (the Dashboard's summary table,
   etc.), shares this same look from here rather than each page hand-
   styling its own <table>, so a future table gets it for free and the
   whole app reads as one consistent design instead of a pile of one-off
   tables. Deliberately CSS-only - no template markup changes - so it
   applies uniformly without touching every page that has a table.
   --------------------------------------------------------------------- */

/* The card wrapping a table (the near-universal pattern in this app) -
   a soft shadow + slightly bigger radius reads as "this content sits on
   its own surface" instead of the flat, barely-there default Bootstrap
   card (1px gray border, 0.25rem radius, no depth at all). */
.card {
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: .6rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .03);
}

table.dataTable,
table.table {
  border-collapse: separate;
  border-spacing: 0;
  font-size: .925rem;
}

/* Header: a clear, quiet break from the body instead of body-colored
   text on a bare white row - reads as "column labels", not just another
   data row, at a glance. A faint brand-accent wash (instead of flat gray)
   plus a slightly heavier accent-colored bottom edge gives it a touch of
   the app's own color without shouting. */
table.dataTable thead th,
table.table thead th {
  background-image: linear-gradient(rgba(var(--brand-accent-rgb), .05), rgba(var(--brand-accent-rgb), .05)), linear-gradient(#f8f9fb, #f8f9fb);
  color: #495057;
  font-weight: 700;
  font-size: .78rem;
  letter-spacing: .03em;
  text-transform: uppercase;
  border-bottom: 2px solid rgba(var(--brand-accent-rgb), .35) !important;
  border-top: none !important;
  padding-top: .7rem;
  padding-bottom: .7rem;
  white-space: nowrap;
}

/* DataTables' own sort-direction carets - shrunk and tightened so they
   read as a small "sort tool" beside the label rather than competing,
   oversized arrows; the active sort direction picks up the brand accent
   and full opacity so it's still obvious which column/direction is live. */
table.dataTable thead th.sorting::before,
table.dataTable thead th.sorting::after,
table.dataTable thead th.sorting_asc::before,
table.dataTable thead th.sorting_asc::after,
table.dataTable thead th.sorting_desc::before,
table.dataTable thead th.sorting_desc::after {
  font-size: .65em;
  opacity: .25;
  transition: opacity .15s ease, color .15s ease;
}

table.dataTable thead th.sorting_asc::before,
table.dataTable thead th.sorting_desc::after {
  opacity: 1;
  color: var(--brand-accent);
}

table.dataTable thead th.sorting:hover::before,
table.dataTable thead th.sorting:hover::after {
  opacity: .5;
}

table.dataTable tbody td,
table.table tbody td {
  padding-top: .6rem;
  padding-bottom: .6rem;
  border-top: 1px solid #f1f3f5;
  vertical-align: middle;
}

/* Striping a touch lighter still than before, barely-there so it guides
   the eye across a row without adding visible gray banding; hover tint
   uses the brand accent instead of plain gray, so a row lighting up on
   hover reads as "this app", not a stock table. */
table.dataTable.table-striped > tbody > tr:nth-of-type(odd) > *,
table.table.table-striped > tbody > tr:nth-of-type(odd) > * {
  background-color: rgba(0, 0, 0, .012);
}

table.dataTable.table-hover > tbody > tr:hover > *,
table.table.table-hover > tbody > tr:hover > * {
  background-color: rgba(var(--brand-accent-rgb), .07);
}

table.dataTable tbody tr:last-child td,
table.table tbody tr:last-child td {
  border-bottom: none;
}

/* A table's own "Total" summary row (tfoot) - a brand-accent tinted band
   with a clear top divider so it reads as a distinct grand-total line,
   not just another (bolded) data row blending into the body above it. */
table.table tfoot tr.table-total-row td {
  background-color: rgba(var(--brand-accent-rgb), .1) !important;
  border-top: 2px solid rgba(var(--brand-accent-rgb), .4);
  border-bottom: none;
  color: #343a40;
  font-weight: 700;
}

/* DataTables' own "Showing X to Y of Z" / length / search controls -
   quieter, smaller text so they read as chrome around the table rather
   than competing with its own header row. */
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter label {
  color: #6c757d;
  font-size: .875rem;
}

.dataTables_wrapper .dataTables_length select,
.dataTables_wrapper .dataTables_filter input {
  border-radius: .4rem;
  border-color: #dee2e6;
}

.dataTables_wrapper .dataTables_filter input:focus,
.dataTables_wrapper .dataTables_length select:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .15);
}

/* Pagination - rounded pill buttons instead of Bootstrap's square-edged
   default, current page tinted with the brand accent so it's obvious at
   a glance which page you're on. */
.dataTables_wrapper .dataTables_paginate .paginate_button {
  border-radius: .4rem !important;
  margin-left: .2rem;
  border-color: transparent !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button.current,
.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
  background: var(--brand-accent) !important;
  border-color: var(--brand-accent) !important;
  color: #fff !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button:hover:not(.current) {
  background: rgba(var(--brand-accent-rgb), .12) !important;
  border-color: transparent !important;
  color: #212529 !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover {
  background: transparent !important;
  color: #adb5bd !important;
}

/* Manufacturer name links (Dashboard + Manufacturers list tables) - no
   underline, brand-accent hover with a subtle sliding highlight so the row's
   primary link reads as clickable without looking like a plain <a> tag. */
.manufacturer-link {
  display: inline-block;
  position: relative;
  color: #212529;
  font-weight: 600;
  text-decoration: none;
  padding: .1rem .05rem;
  transition: color .15s ease;
}
.manufacturer-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 2px;
  border-radius: 2px;
  background: var(--brand-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .18s ease;
}
.manufacturer-link:hover,
.manufacturer-link:focus {
  color: var(--brand-accent);
  text-decoration: none;
}
.manufacturer-link:hover::after,
.manufacturer-link:focus::after {
  transform: scaleX(1);
}

/* Product/module name links (Modules table, module detail pages) - plain
   until hovered, then underlines and picks up the brand accent so it
   reads as clickable without every row looking like a wall of blue
   underlined links. */
.product-link {
  color: #212529;
  font-weight: 600;
  text-decoration: none;
}
.product-link:hover,
.product-link:focus {
  color: var(--brand-accent);
  text-decoration: underline;
}

/* Modules table's per-row "syncing" loader (Success column, live job
   progress) - brand-accent spinner ring with the in-progress count in
   the secondary brand color, instead of Bootstrap's stock blue on both. */
.sync-loader-spinner {
  color: var(--brand-accent);
}
.sync-loader-count {
  color: var(--brand-secondary);
}

/* Table checkboxes (select-all header + per-row selection) - a custom
   rounded checkbox instead of the tiny, inconsistent native browser
   default, checked state filled with the brand accent with a small
   white tick. Excludes .form-check-input (the Manufacturers table's
   Active/Inactive toggle switch) - that one needs to stay a real
   Bootstrap pill switch, not a checkbox square. */
table.dataTable input[type="checkbox"]:not(.form-check-input) {
  appearance: none;
  -webkit-appearance: none;
  box-sizing: border-box;
  display: inline-flex;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0;
  border: 1.5px solid #ced4da;
  border-radius: .3rem;
  background-color: #fff;
  vertical-align: middle;
  cursor: pointer;
  position: relative;
  top: -1px;
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
table.dataTable input[type="checkbox"]:not(.form-check-input):hover {
  border-color: var(--brand-accent);
}
table.dataTable input[type="checkbox"]:not(.form-check-input):focus-visible {
  outline: none;
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .2);
}
table.dataTable input[type="checkbox"]:not(.form-check-input):checked {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
}
/* Tick centered via transform (not hard-coded offsets) so it stays dead
   center regardless of the checkbox's exact rendered box size. */
table.dataTable input[type="checkbox"]:not(.form-check-input):checked::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 46%;
  width: .3rem;
  height: .55rem;
  border: solid #fff;
  border-width: 0 .135rem .135rem 0;
  transform: translate(-50%, -50%) rotate(45deg);
}

/* Modules table's own loading state (see modules_list.html) - swapped
   in for DataTables' default emptyTable text (literally the plain,
   unstyled word "Loading...") while the first AJAX draw is in flight,
   then hidden in favor of the real table (#modules-table-wrap) the
   moment initComplete fires. Brand-colored spinner (Bootstrap's
   .spinner-border re-colored via border-color, same trick used for
   this app's buttons elsewhere) sized up from Bootstrap's own default
   (would otherwise read as barely-there on an empty page) so it's
   immediately, unmistakably visible rather than something you could
   glance past. */
.modules-table-loading .spinner-border {
  width: 3rem;
  height: 3rem;
  border-width: .35em;
  color: var(--brand-accent);
}

/* App-wide DataTables loading placeholder (see app.js's top-level
   $.fn.dataTable.defaults override) - every table's own default empty/
   loading state, unless a page overrides `language.emptyTable` itself
   with something more specific (e.g. modules_list.html distinguishes
   "still loading" from "genuinely 0 rows"; most other tables don't need
   that distinction and just want this to look nice either way).
   Brand-colored spinner, sized up from Bootstrap's own default (which
   reads as barely-there on an otherwise-empty table) so it's
   immediately, unmistakably visible. */
.dt-loading-placeholder .spinner-border {
  width: 2.5rem;
  height: 2.5rem;
  border-width: .3em;
  color: var(--brand-accent);
}
