/* ==========================================================================
   NetDash - styles layered on top of Tabler.
   Motion is used to carry meaning: what changed, what is live, what is
   loading. Everything here honours prefers-reduced-motion.
   ========================================================================== */

:root {
  --nd-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --nd-fast: 140ms;
  --nd-med: 260ms;
  --nd-slow: 420ms;
}

/* --------------------------------------------------------------------------
   Brand
   -------------------------------------------------------------------------- */
.nd-brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--tblr-primary), var(--tblr-purple));
  color: #fff;
  font-size: 1.1rem;
  box-shadow: 0 2px 10px rgba(var(--tblr-primary-rgb), 0.4);
  transition: transform var(--nd-med) var(--nd-ease), box-shadow var(--nd-med) var(--nd-ease);
}
.navbar-brand a:hover .nd-brand-mark {
  transform: rotate(-8deg) scale(1.06);
  box-shadow: 0 4px 18px rgba(var(--tblr-primary-rgb), 0.55);
}
.nd-brand-text {
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--tblr-body-color);
}
.nd-avatar {
  background: linear-gradient(135deg, var(--tblr-primary), var(--tblr-cyan));
  color: #fff;
}

/* Keep Tabler's content containers centred, but make the page shell and both
   navbar bands reach the viewport edges. Tabler's persisted boxed layout can
   otherwise leave a visible gutter around the whole application. */
html,
body {
  margin: 0 !important;
  padding: 0 !important;
  width: 100%;
}
.layout-boxed {
  padding: 0 !important;
}
body > .page,
.layout-boxed .page {
  width: 100% !important;
  min-width: 100% !important;
  max-width: none !important;
  margin: 0 !important;
  border-left: 0 !important;
  border-right: 0 !important;
  border-radius: 0 !important;
}
body > .page > header,
body > .page > header .navbar,
.layout-boxed .page > header,
.layout-boxed .page > header .navbar {
  width: 100% !important;
  margin-inline: 0 !important;
}
body > .page > .navbar:first-child,
.layout-boxed .page > .navbar:first-child {
  border-radius: 0 !important;
}

/* Theme toggle: show the icon for the theme you would switch *to*. */
[data-bs-theme='dark'] .nd-theme-light-icon { display: none; }
[data-bs-theme='light'] .nd-theme-dark-icon { display: none; }

/* --------------------------------------------------------------------------
   Page + card entrance
   -------------------------------------------------------------------------- */
@keyframes nd-fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes nd-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.page-body .card,
.page-body .nd-animate {
  animation: nd-fade-up var(--nd-med) var(--nd-ease) both;
}
/* Stagger, so a grid of cards resolves rather than snapping in at once. */
.page-body .row > *:nth-child(1) .card { animation-delay: 0ms; }
.page-body .row > *:nth-child(2) .card { animation-delay: 40ms; }
.page-body .row > *:nth-child(3) .card { animation-delay: 80ms; }
.page-body .row > *:nth-child(4) .card { animation-delay: 120ms; }
.page-body .row > *:nth-child(5) .card { animation-delay: 160ms; }
.page-body .row > *:nth-child(6) .card { animation-delay: 200ms; }

.card {
  transition: border-color var(--nd-med) var(--nd-ease), box-shadow var(--nd-med) var(--nd-ease);
}
.nd-card-hover:hover {
  border-color: rgba(var(--tblr-primary-rgb), 0.5);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
}

/* --------------------------------------------------------------------------
   Status indicators
   -------------------------------------------------------------------------- */
.nd-dot {
  display: inline-block;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  flex: 0 0 auto;
  position: relative;
}
.nd-dot-up      { background: var(--tblr-green); }
.nd-dot-down    { background: var(--tblr-red); }
.nd-dot-warn    { background: var(--tblr-orange); }
.nd-dot-unknown { background: var(--tblr-gray-500); }

/* A live "up" state breathes; a down state pulses urgently. */
@keyframes nd-pulse-ring {
  0%   { box-shadow: 0 0 0 0 currentColor; opacity: 0.7; }
  70%  { box-shadow: 0 0 0 0.5rem transparent; opacity: 0; }
  100% { box-shadow: 0 0 0 0 transparent; opacity: 0; }
}
.nd-dot-up::after,
.nd-dot-down::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  animation: nd-pulse-ring 2s var(--nd-ease) infinite;
}
.nd-dot-up::after   { color: var(--tblr-green); }
.nd-dot-down::after { color: var(--tblr-red); animation-duration: 1.1s; }

/* Established / idle / connect states for BGP sessions. */
.nd-state {
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   Live data refresh: flash a value that just changed
   -------------------------------------------------------------------------- */
@keyframes nd-flash {
  0%   { background-color: rgba(var(--tblr-primary-rgb), 0.28); }
  100% { background-color: transparent; }
}
.nd-changed {
  animation: nd-flash 1.1s var(--nd-ease);
  border-radius: 4px;
}

/* --------------------------------------------------------------------------
   Loading states
   -------------------------------------------------------------------------- */
@keyframes nd-shimmer {
  from { background-position: -400px 0; }
  to   { background-position: 400px 0; }
}
.nd-skeleton {
  display: block;
  min-height: 0.9rem;
  border-radius: 4px;
  background: linear-gradient(
    90deg,
    var(--tblr-border-color) 0px,
    var(--tblr-bg-surface-secondary) 60px,
    var(--tblr-border-color) 120px
  );
  background-size: 800px 100%;
  animation: nd-shimmer 1.3s linear infinite;
}

@keyframes nd-spin { to { transform: rotate(360deg); } }
.nd-spin { animation: nd-spin 900ms linear infinite; display: inline-block; }

/* A thin progress bar pinned to the top of the viewport during fetches. */
#nd-progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 0;
  background: linear-gradient(90deg, var(--tblr-primary), var(--tblr-cyan));
  box-shadow: 0 0 8px rgba(var(--tblr-primary-rgb), 0.8);
  z-index: 2000;
  transition: width var(--nd-med) var(--nd-ease), opacity var(--nd-med) var(--nd-ease);
  opacity: 0;
  pointer-events: none;
}
#nd-progress.nd-active { opacity: 1; }

/* --------------------------------------------------------------------------
   Toasts
   -------------------------------------------------------------------------- */
#nd-toasts {
  position: fixed;
  bottom: 1rem;
  right: 1rem;
  z-index: 1080;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: min(26rem, calc(100vw - 2rem));
}
@keyframes nd-toast-in {
  from { opacity: 0; transform: translateX(1.5rem) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
.nd-toast {
  animation: nd-toast-in var(--nd-med) var(--nd-ease) both;
  transition: opacity var(--nd-med) var(--nd-ease), transform var(--nd-med) var(--nd-ease);
}
.nd-toast.nd-leaving { opacity: 0; transform: translateX(1.5rem); }

/* --------------------------------------------------------------------------
   Login
   -------------------------------------------------------------------------- */
.nd-auth-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  background:
    radial-gradient(1000px 500px at 15% -10%, rgba(var(--tblr-primary-rgb), 0.16), transparent 60%),
    radial-gradient(800px 400px at 90% 110%, rgba(var(--tblr-purple-rgb), 0.14), transparent 60%);
}
.nd-auth-card { animation: nd-fade-up var(--nd-slow) var(--nd-ease) both; }

/* One box per digit for the TOTP code. */
.nd-otp-input {
  font-size: 1.5rem;
  letter-spacing: 0.75em;
  text-align: center;
  font-family: var(--tblr-font-monospace);
  padding-left: 0.75em;
}

@keyframes nd-shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); }
  40%, 60% { transform: translateX(4px); }
}
.nd-shake { animation: nd-shake 500ms var(--nd-ease); }

/* --------------------------------------------------------------------------
   Tables and code
   -------------------------------------------------------------------------- */
.nd-mono {
  font-family: var(--tblr-font-monospace);
  font-size: 0.8125rem;
}
.nd-truncate {
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.table tbody tr { transition: background-color var(--nd-fast) var(--nd-ease); }

/* One polished visual level beneath a category summary, while retaining the
   complete monitor table and its controls. */
.nd-category-summary > td {
  border-bottom: 0;
  background: color-mix(in srgb, var(--tblr-primary) 3%, var(--tblr-bg-surface));
}
.nd-category-cell {
  position: relative;
  padding: 0.25rem 0.85rem 0.9rem 1.65rem !important;
  background: color-mix(in srgb, var(--tblr-primary) 3%, var(--tblr-bg-surface));
}
.nd-category-cell::before {
  content: '';
  position: absolute;
  top: -0.05rem;
  left: 0.75rem;
  width: 0.72rem;
  height: 1.25rem;
  border-left: 1px solid color-mix(in srgb, var(--tblr-primary) 55%, var(--tblr-border-color));
  border-bottom: 1px solid color-mix(in srgb, var(--tblr-primary) 55%, var(--tblr-border-color));
  border-bottom-left-radius: 0.45rem;
  pointer-events: none;
}
.nd-category-inset {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--tblr-border-color);
  border-left: 3px solid var(--tblr-primary);
  border-radius: var(--tblr-border-radius-lg);
  background: var(--tblr-bg-surface);
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.1);
}
.nd-category-inset thead th {
  font-size: 0.7rem;
  background: color-mix(in srgb, var(--tblr-primary) 4%, var(--tblr-bg-surface-secondary));
}
.nd-category-inset tbody tr:last-child > td { border-bottom: 0; }

@media (max-width: 575.98px) {
  .nd-category-cell {
    padding-left: 0.65rem !important;
    padding-right: 0.45rem !important;
  }
  .nd-category-cell::before { display: none; }
}

/* The config editor and console want a real terminal feel. */
.nd-editor {
  font-family: var(--tblr-font-monospace);
  font-size: 0.8125rem;
  line-height: 1.55;
  tab-size: 4;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
  min-height: 28rem;
}
.nd-console {
  background: #0b0f16;
  color: #d3dae6;
  font-family: var(--tblr-font-monospace);
  font-size: 0.8125rem;
  line-height: 1.5;
  padding: 0.75rem 1rem;
  border-radius: var(--tblr-border-radius);
  overflow-y: auto;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
  min-height: 20rem;
}
.nd-console-line-err { color: #ff8a8a; }
.nd-console-line-ok  { color: #8ce99a; }
.nd-diagnostic-output {
  color: #f1f5f9 !important;
  background: #111827;
  line-height: 1.55;
}

/* Any wide element must scroll inside itself, never the page. */
.nd-scroll-x { overflow-x: auto; }

/* --------------------------------------------------------------------------
   Empty states - "nothing here" should still feel alive, not broken
   -------------------------------------------------------------------------- */
.nd-empty {
  text-align: center;
  padding: 3rem 1.5rem;
  animation: nd-fade-up var(--nd-med) var(--nd-ease) both;
}
.nd-empty-orb {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  margin-bottom: 1.25rem;
  background: linear-gradient(135deg,
    rgba(var(--tblr-primary-rgb), 0.18),
    rgba(var(--tblr-purple-rgb), 0.12));
  color: var(--tblr-primary);
  font-size: 1.85rem;
  animation: nd-float 4s var(--nd-ease) infinite;
}
@keyframes nd-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
.nd-empty-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(var(--tblr-primary-rgb), 0.35);
  animation: nd-empty-expand 3s var(--nd-ease) infinite;
}
.nd-empty-ring-2 { animation-delay: 1.5s; }
@keyframes nd-empty-expand {
  0%   { transform: scale(1);   opacity: 0.7; }
  100% { transform: scale(1.7); opacity: 0; }
}
.nd-empty-title {
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--tblr-body-color);
  /* A soft sweep across the text, as requested for empty tables. */
  background: linear-gradient(90deg,
    var(--tblr-body-color) 0%,
    var(--tblr-primary) 50%,
    var(--tblr-body-color) 100%);
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: nd-text-sweep 4s linear infinite;
}
@keyframes nd-text-sweep {
  to { background-position: 200% center; }
}
.nd-empty-subtitle {
  color: var(--tblr-secondary);
  font-size: 0.875rem;
  margin-top: 0.35rem;
  max-width: 30rem;
  margin-left: auto;
  margin-right: auto;
}

/* --------------------------------------------------------------------------
   Maintenance banner
   -------------------------------------------------------------------------- */
@keyframes nd-stripe-drift {
  to { background-position: 40px 0; }
}
.nd-maintenance {
  background-image: repeating-linear-gradient(
    45deg,
    rgba(var(--tblr-warning-rgb), 0.14) 0 10px,
    transparent 10px 20px
  );
  background-size: 40px 40px;
  animation: nd-stripe-drift 1.6s linear infinite;
  border-left: 3px solid var(--tblr-warning);
}

/* --------------------------------------------------------------------------
   Uptime bars
   -------------------------------------------------------------------------- */
.nd-uptime-bar {
  display: flex;
  gap: 2px;
  align-items: flex-end;
  height: 2rem;
}
.nd-uptime-bar > span {
  flex: 1 1 auto;
  min-width: 2px;
  border-radius: 2px;
  background: var(--tblr-gray-500);
  transition: transform var(--nd-fast) var(--nd-ease);
}
.nd-uptime-bar > span:hover { transform: scaleY(1.15); }
.nd-uptime-up      { background: var(--tblr-green) !important; height: 100%; }
.nd-uptime-partial { background: var(--tblr-orange) !important; height: 100%; }
.nd-uptime-down    { background: var(--tblr-red) !important; height: 100%; }
.nd-uptime-maint   { background: var(--tblr-blue) !important; height: 100%; }
.nd-uptime-none    { background: var(--tblr-border-color) !important; height: 35%; }

/* --------------------------------------------------------------------------
   Daily uptime strip (status-page style)
   -------------------------------------------------------------------------- */
.nd-days-strip {
  display: flex;
  gap: 2px;
  align-items: stretch;
  width: 100%;
}
.nd-day {
  flex: 1 1 0;
  min-width: 3px;
  border-radius: 2px;
  background: var(--tblr-border-color);
  transition: transform var(--nd-fast) var(--nd-ease), filter var(--nd-fast) var(--nd-ease);
  display: block;
  text-decoration: none;
  position: relative;
}
/* Lift the hovered day out of the row so it reads as the active one. */
.nd-day:hover,
.nd-day:focus-visible {
  transform: scaleY(1.18) scaleX(1.6);
  filter: brightness(1.15);
  z-index: 2;
  outline: none;
}
.nd-day-clickable { cursor: pointer; }

.nd-day-up      { background: var(--tblr-green); }
.nd-day-partial { background: var(--tblr-orange); }
.nd-day-down    { background: var(--tblr-red); }
/* Maintenance is deliberately orange, not red: it was planned. */
.nd-day-maint   { background: #f59f00; }
.nd-day-none    { background: var(--tblr-border-color); opacity: 0.55; }

.nd-days-legend {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 0.4rem;
  font-size: 0.75rem;
  color: var(--tblr-secondary);
}
.nd-days-legend-mid { font-size: 0.8125rem; }

/* Tooltip shown while hovering a day. */
.nd-day-tip {
  position: fixed;
  z-index: 1080;
  min-width: 11rem;
  max-width: 22rem;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  background: var(--tblr-bg-surface);
  border: 1px solid var(--tblr-border-color);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.24);
  font-size: 0.8125rem;
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--nd-fast) var(--nd-ease), transform var(--nd-fast) var(--nd-ease);
}
.nd-day-tip.nd-visible { opacity: 1; transform: translateY(0); }
.nd-day-tip-date { font-weight: 600; margin-bottom: 0.15rem; }
.nd-day-tip-detail { color: var(--tblr-secondary); }
.nd-day-tip-incidents {
  margin-top: 0.45rem;
  padding-top: 0.45rem;
  border-top: 1px solid var(--tblr-border-color);
  color: var(--tblr-secondary);
}
.nd-day-tip-hint { margin-top: 0.35rem; color: var(--tblr-primary); font-size: 0.75rem; }

/* --------------------------------------------------------------------------
   Sparklines / mini metrics
   -------------------------------------------------------------------------- */
.nd-metric-value {
  font-size: 1.6rem;
  font-weight: 600;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.nd-metric-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--tblr-secondary);
}

/* Usage meters that colour by severity. */
.nd-meter { height: 0.35rem; border-radius: 999px; overflow: hidden; background: var(--tblr-border-color); }
.nd-meter > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  transition: width var(--nd-slow) var(--nd-ease), background-color var(--nd-med) var(--nd-ease);
}

/* --------------------------------------------------------------------------
   Mobile
   -------------------------------------------------------------------------- */
@media (max-width: 575.98px) {
  .nd-truncate { max-width: 11rem; }
  .nd-metric-value { font-size: 1.3rem; }
  .page-body .card { animation-delay: 0ms !important; }
}

/* --------------------------------------------------------------------------
   Respect the user's motion preference.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
/* Container console: isolated text surface with a visible focus state. */
.nd-console {
  min-height: 65vh;
  max-height: 70vh;
  overflow: auto;
  padding: 1rem;
  color: #cfe8d5;
  background: #080d0a;
  font: 14px/1.35 var(--tblr-font-monospace, monospace);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  cursor: text;
  outline: 0;
}
.nd-console:focus { box-shadow: inset 0 0 0 2px rgba(47, 179, 68, .5); }
.nd-console pre { display: inline; margin: 0; color: inherit; font: inherit; white-space: pre-wrap; }
.nd-console-cursor { display: inline-block; width: .55em; height: 1.05em; margin-left: 1px; vertical-align: -.15em; background: #7bf195; animation: nd-cursor 1s steps(1) infinite; }
@keyframes nd-cursor { 50% { opacity: 0; } }
.nd-brand-logo { display: block; width: auto; max-width: 132px; height: 32px; object-fit: contain; }

/* Tabler styles .alert as display:flex with gap:1rem. Every in-flow child of a
   flex container becomes a flex item, and an inline element is no exception -
   so an alert written as one run of prose turns each <i>, <strong> and <a>
   into its own item with a 1rem gap beside it, and reads as "2   nodes
   require a reboot:   ger-02 ,   ger-05 ." rather than as a sentence.
   Tabler's own examples avoid this by wrapping the body in a single element;
   most alerts here are plain prose and do not. Restoring block flow fixes them
   all at once, and an alert that genuinely wants the flex layout still gets it
   by asking for .d-flex, which Bootstrap declares !important. */
.alert { display: block; }

/* Per-node "what changed" timeline: a vertical rail with a dot per entry. */
.nd-timeline { position: relative; }
.nd-timeline-row {
  position: relative;
  display: grid;
  grid-template-columns: 8.5rem 2rem 1fr;
  gap: 0 .75rem;
  padding: .5rem 0;
}
.nd-timeline-row:not(:last-child)::before {
  content: '';
  position: absolute;
  left: calc(8.5rem + 1rem - 1px);
  top: 2rem;
  bottom: -.5rem;
  width: 2px;
  background: var(--tblr-border-color);
}
.nd-timeline-time { color: var(--tblr-secondary-color); font-size: .8125rem; padding-top: .3rem; text-align: right; }
.nd-timeline-dot {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .9rem;
  z-index: 1;
}
.nd-timeline-body { padding-top: .25rem; }

/* --------------------------------------------------------------------------
   Drag-and-drop row ordering
   -------------------------------------------------------------------------- */
.nd-grip {
  cursor: grab;
  color: var(--tblr-secondary-color);
  background: none;
  border: 0;
  padding: 0 .25rem;
  line-height: 1;
  border-radius: 4px;
  transition: color var(--nd-fast) var(--nd-ease), background-color var(--nd-fast) var(--nd-ease);
}
.nd-grip:hover { color: var(--tblr-primary); background: rgba(var(--tblr-primary-rgb), .1); }
.nd-grip:active { cursor: grabbing; }
.nd-grip:focus-visible {
  outline: 2px solid var(--tblr-primary);
  outline-offset: 2px;
  color: var(--tblr-primary);
}
/* The row being carried: lifted, dimmed, and clearly not in place yet. */
tr.nd-dragging,
.nd-dragging {
  opacity: .55;
  background: rgba(var(--tblr-primary-rgb), .07) !important;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .22);
}
[data-reorder] tr { transition: transform var(--nd-fast) var(--nd-ease); }

/* --------------------------------------------------------------------------
   Dashboard polish
   -------------------------------------------------------------------------- */

/* Figures that change between polls must not make the column jitter. */
.nd-tnum { font-variant-numeric: tabular-nums; }

/* Meters grow from empty on load, so the eye is drawn along the bar rather
   than having to read a number that was already there. The custom property
   carries the final width; the keyframe animates to it. */
.nd-meter-grow > span {
  animation: nd-meter-fill var(--nd-slow) var(--nd-ease) both;
}
@keyframes nd-meter-fill {
  from { width: 0 !important; }
}

/* A long fleet scrolls under its own header rather than losing it. */
.card-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--tblr-card-bg, var(--tblr-bg-surface));
  /* Tabler draws the header rule with a border that sticky positioning drops. */
  box-shadow: inset 0 -1px 0 var(--tblr-border-color);
}

/* Row hover: a left accent rather than a wash, so the row being read is
   obvious without the table turning into a block of colour. */
.card-table tbody tr {
  transition: background-color var(--nd-fast) var(--nd-ease),
              box-shadow var(--nd-fast) var(--nd-ease);
}
.card-table tbody tr:hover {
  background-color: rgba(var(--tblr-primary-rgb), .04);
  box-shadow: inset 3px 0 0 var(--tblr-primary);
}
/* A row mid-drag keeps its lifted treatment instead of the hover accent. */
.card-table tbody tr.nd-dragging:hover { box-shadow: 0 6px 20px rgba(0, 0, 0, .22); }

/* --------------------------------------------------------------------------
   Navigation chrome
   -------------------------------------------------------------------------- */

/* An active indicator that slides rather than blinks. The underline is drawn
   with a transform so it animates on the compositor, and it is anchored to the
   link rather than the label so it does not jump between different word
   lengths. */
.navbar-nav .nav-item > .nav-link {
  position: relative;
  transition: color var(--nd-fast) var(--nd-ease);
}
.navbar-nav .nav-item > .nav-link::after {
  content: '';
  position: absolute;
  left: .5rem;
  right: .5rem;
  bottom: 0;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--tblr-primary);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--nd-med) var(--nd-ease);
}
.navbar-nav .nav-item.active > .nav-link::after,
.navbar-nav .nav-item > .nav-link:hover::after,
.navbar-nav .nav-item > .nav-link:focus-visible::after {
  transform: scaleX(1);
}
.navbar-nav .nav-item.active > .nav-link { color: var(--tblr-primary); }

/* The icon leads the eye to the section being pointed at. */
.navbar-nav .nav-link-icon {
  display: inline-block;
  transition: transform var(--nd-med) var(--nd-ease);
}
.navbar-nav .nav-item > .nav-link:hover .nav-link-icon { transform: translateY(-1px) scale(1.08); }

/* Menus resolve downward instead of appearing fully formed. */
.dropdown-menu.show {
  animation: nd-dropdown-in var(--nd-fast) var(--nd-ease) both;
}
@keyframes nd-dropdown-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
.dropdown-item {
  transition: background-color var(--nd-fast) var(--nd-ease),
              padding-left var(--nd-fast) var(--nd-ease);
}
.dropdown-item:hover:not(.active) { padding-left: 1.25rem; }

/* The theme control turns over as it is used, which is the one place a little
   personality costs nothing. */
#nd-theme-toggle i { transition: transform var(--nd-slow) var(--nd-ease); display: inline-block; }
#nd-theme-toggle:hover i { transform: rotate(-25deg) scale(1.12); }

/* The account menu reads as a control rather than as text. */
.navbar-nav .nav-item.dropdown .avatar { transition: box-shadow var(--nd-med) var(--nd-ease); }
.navbar-nav .nav-item.dropdown:hover .avatar {
  box-shadow: 0 0 0 3px rgba(var(--tblr-primary-rgb), .25);
}

/* Keyboard focus is visible on every navigation control, not only the ones
   Tabler styles by default. */
.navbar a:focus-visible,
.dropdown-item:focus-visible {
  outline: 2px solid var(--tblr-primary);
  outline-offset: -2px;
  border-radius: 4px;
}
