/* =====================================================
   TehGuys Modern Theme
   Cinematic, High-Contrast, Premium Design System
   Supports Light & Dark modes

   NOTE: Structural tokens (palette, radii, spacing,
   typography, transitions) live in tokens.css (SSOT).
   This file only defines theme-specific vars and
   consumes tokens — it does NOT redefine any var
   that already exists in tokens.css.
   ===================================================== */

/* =====================================================
   CSS Variables - Light Theme (Default)
   ===================================================== */
:root {
  /* >>> gen:theme-root >>> AUTO-GENERATED by scripts/gen_design_tokens.py — edit design-tokens.md */
  /* Primary Light Palette */
  --bg-primary:    #F6F1E4;
  --bg-secondary:  #FFFFFF;
  --bg-tertiary:   #DDD8CC;
  --bg-card:       #FFFFFF;
  --bg-card-hover: #F9F6EE;
  --bg-elevated:   #FFFFFF;
  --bg-input:      #FFFFFF;

  /* Surface Colors */
  --surface-dark:      #DDD8CC;
  --surface-medium:    #E5E1D6;
  --surface-light:     #EDE8DA;
  --surface-highlight: #F2EDE2;

  /* Border Colors */
  --border-dark:      #C5BFB2;
  --border-medium:    #D0C9BC;
  --border-light:     #DDD8CC;
  --border-highlight: #E5E0D4;

  /* Text Colors */
  --text-primary:     #0E2233;
  --text-secondary:   #1A3348;
  --text-tertiary:    #4A6070;
  --text-muted:       #6A7D8A;
  --text-placeholder: #7A8D9A;

  /* Semantic accent vars — mapped to Craft palette */
  --accent-red:    #dc3545;
  --accent-green:  #1E8F4E;
  --accent-yellow: #ffc107;
  --accent-purple: #6f42c1;

  /* Gradient identity — one gradient used everywhere */
  --gradient-primary: var(--craft-gradient-accent);

  /* Accent contrast + focus role (themes.css overrides per palette) */
  --accent-contrast:   #0E2233; /* label ON a solid accent; Electric Green is light -> ink */
  --focus-ring:        #17703D; /* Deep Forest: >=3:1 on all 26 light surfaces */
  --focus-ring-offset: 2px;

  /* Marketing theme — public surfaces only, never product UI */
  --marketing-hero-gradient: linear-gradient(135deg, #3730A3 0%, #4F46E5 50%, #6366F1 100%);
  --marketing-hero-ink:      #4F46E5;

  /* Avatar sizes */
  --avatar-sm: 36px;
  --avatar-md: 48px;
  --avatar-lg: 128px;

  /* Legacy vars for compatibility */
  --bg-color:     #F6F1E4;
  --text-color:   #0E2233;
  --card-bg:      #FFFFFF;
  --footer-bg:    #F6F1E4;
  --muted-color:  #6A7D8A;
  --link-color:   var(--craft-green-text);
  --border-color: #DDD8CC;

  /* Shadows — tinted to Craft Indigo */
  --shadow-sm:         0 1px 3px rgba(15, 23, 42, 0.08);
  --shadow-md:         0 4px 12px rgba(15, 23, 42, 0.10);
  --shadow-lg:         0 10px 24px rgba(15, 23, 42, 0.12);
  --shadow-xl:         0 18px 36px rgba(15, 23, 42, 0.16);
  --shadow-glow:       none;
  --shadow-card:       0 1px 3px rgba(15, 23, 42, 0.08);
  --shadow-card-hover: 0 6px 16px rgba(15, 23, 42, 0.12);

  /* Glass Morphism (Premium) */
  --glass-border:       1px solid rgba(221, 216, 204, 0.40);
  --glass-shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.2);

  /* Tinted Shadows (Alternative Depth) */
  --shadow-tinted-sm: 0 2px 8px rgba(30, 143, 78, 0.08);
  --shadow-tinted-md: 0 4px 16px rgba(30, 143, 78, 0.12);
  --shadow-tinted-lg: 0 8px 32px rgba(30, 143, 78, 0.15);
/* <<< gen:theme-root <<< */
}

/* =====================================================
   CSS Variables - Dark Theme Override
   ===================================================== */
body.dark-mode {
  /* >>> gen:theme-dark >>> AUTO-GENERATED by scripts/gen_design_tokens.py — edit design-tokens.md */
  /* Primary Dark Palette */
  --bg-primary:    #081628;
  --bg-secondary:  #0D1E35;
  --bg-tertiary:   #0A1825;
  --bg-card:       #0E2233;
  --bg-card-hover: #132844;
  --bg-elevated:   #163050;
  --bg-input:      #0D1E35;

  /* Surface Colors */
  --surface-dark:      #0A0D1A;
  --surface-medium:    #0A1A2E;
  --surface-light:     #102038;
  --surface-highlight: #152840;

  /* Border Colors */
  --border-dark:      #0E2233;
  --border-medium:    #1A3348;
  --border-light:     #254560;
  --border-highlight: #30587A;

  /* Text Colors */
  --text-primary:     #F6F1E4;
  --text-secondary:   #C8D8E8;
  --text-tertiary:    #7A9AB5;
  --text-muted:       #506070;
  --text-placeholder: #60788A;

  /* Focus role — Deep Forest is 2.18:1 on the dark activities band */
  --focus-ring: #53E867; /* Electric Green: >=3:1 on all 26 dark surfaces */

  /* Legacy vars for compatibility */
  --bg-color:     #081628;
  --text-color:   #F6F1E4;
  --card-bg:      #0E2233;
  --footer-bg:    #0D1E35;
  --muted-color:  #506070;
  --border-color: #1A3348;

  /* Shadows — darker for dark mode */
  --shadow-sm:         0 2px 8px rgba(0, 0, 0, 0.5);
  --shadow-md:         0 4px 16px rgba(0, 0, 0, 0.6);
  --shadow-lg:         0 8px 32px rgba(0, 0, 0, 0.7);
  --shadow-xl:         0 16px 48px rgba(0, 0, 0, 0.8);
  --shadow-glow:       none;
  --shadow-card:       0 4px 20px rgba(0, 0, 0, 0.5);
  --shadow-card-hover: 0 8px 30px rgba(0, 0, 0, 0.6);
  --shadow-tinted-sm:  0 2px 8px rgba(83, 232, 103, 0.18);
  --shadow-tinted-md:  0 4px 16px rgba(83, 232, 103, 0.24);
  --shadow-tinted-lg:  0 8px 32px rgba(83, 232, 103, 0.30);
/* <<< gen:theme-dark <<< */
}

/* =====================================================
   Global Reset & Base Styles
   ===================================================== */
*, *::before, *::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  overflow-x: hidden;
}

body {
  font-family: var(--font-family);
  background: var(--bg-primary);
  color: var(--text-primary);
  margin: 0;
  padding: 0;
  /* NO overflow-x here. Per spec, `overflow-x: hidden` forces overflow-y to
     compute to `auto`, which made <body> a scroll container that never
     actually scrolls (scrollHeight === clientHeight) while <html> did the
     real scrolling. position:sticky resolves against its nearest scrolling
     ancestor, so every sticky descendant in the app silently never engaged -
     measured on activity_detail: a sticky element scrolled away to y=-261
     instead of pinning. `html` above already sets overflow-x: hidden, so
     horizontal scroll is still clipped and nothing is lost. */
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Bridge to Bootstrap variables */
  --bs-body-bg: var(--bg-primary);
  --bs-body-color: var(--text-primary);
  --bs-link-color: var(--link-color);
  --bs-border-color: var(--border-color);
}

.skip-link {
  position: absolute;
  top: var(--space-sm);
  left: var(--space-sm);
  z-index: 2000;
  padding: 0.875rem 1.125rem;
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--accent-blue);
  border: 2px solid var(--accent-blue);
  box-shadow: var(--shadow-lg);
  font-weight: 700;
  transform: translateY(-180%);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--transition-base), opacity var(--transition-base);
}

.skip-link:focus,
.skip-link:focus-visible {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}

a {
  color: var(--craft-indigo);
  text-decoration: none;
  transition: color var(--transition-fast);
}

a:hover {
  color: var(--craft-indigo-hover);
}

/* =====================================================
   Card Components
   ===================================================== */
.card, .list-group-item, .alert, .dropdown-menu {
  background: var(--bg-card);
  border: 1px solid var(--border-medium);
  color: var(--text-primary);
}


/* Text utilities */
.text-muted, small, .form-text {
  color: var(--text-muted) !important;
}

/* Footer */
footer {
  background-color: var(--footer-bg);
  color: var(--text-secondary);
}

/* Nav tabs/pills */
.nav-tabs .nav-link, .nav-pills .nav-link {
  color: var(--text-tertiary);
  border: none;
  padding: var(--space-md) var(--space-lg);
  border-radius: var(--radius-md);
  transition: all var(--transition-fast);
}

.nav-tabs .nav-link:hover, .nav-pills .nav-link:hover {
  color: var(--text-primary);
  background: var(--surface-light);
}

.nav-tabs .nav-link.active, .nav-pills .nav-link.active {
  background: var(--craft-indigo);
  color: var(--accent-contrast, #0E2233);
}

/* Dropdown items */
.dropdown-menu {
  background: var(--bg-card);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--space-sm);
}

.dropdown-menu .dropdown-item {
  color: var(--text-secondary);
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius-sm);
  transition: all var(--transition-fast);
}

.dropdown-menu .dropdown-item:hover, .dropdown-menu .dropdown-item:focus {
  background: var(--surface-light);
  color: var(--text-primary);
}

/* Forms */
.form-control,
.form-select,
.input-group-text,
textarea,
input[type="text"],
input[type="search"],
input[type="email"],
input[type="number"],
input[type="password"],
input[type="date"],
input[type="time"] {
  background: var(--bg-input) !important;
  color: var(--text-primary) !important;
  border: 1px solid var(--border-medium) !important;
  border-radius: var(--radius-md) !important;
  padding: var(--space-md) !important;
  transition: all var(--transition-fast) !important;
}

/* No resizable components anywhere in the app - a user-draggable resize
   handle on a textarea can be stretched to overlap surrounding layout
   (buttons, page title) with nothing constraining it. */
textarea {
  resize: none !important;
}

.form-control:focus,
.form-select:focus,
input:focus,
textarea:focus {
  outline: none !important;
  border-color: var(--craft-indigo) !important;
  box-shadow: 0 0 0 3px var(--craft-indigo-tint) !important;
}

.form-control::placeholder,
textarea::placeholder {
  color: var(--text-placeholder) !important;
}

.form-label {
  color: var(--text-secondary);
  font-weight: 500;
  margin-bottom: var(--space-sm);
}

.form-check-label {
  color: var(--text-secondary);
}

.form-check-input {
  background-color: var(--bg-input);
  border-color: var(--border-medium);
}

.form-check-input:checked {
  background-color: var(--craft-indigo);
  border-color: var(--craft-indigo);
}

/* Background utilities */
.bg-light {
  background-color: var(--surface-light) !important;
  color: var(--text-primary) !important;
}

.bg-white {
  background-color: var(--bg-card) !important;
  color: var(--text-primary) !important;
}

.text-dark {
  color: var(--text-primary) !important;
}

a.text-dark {
  color: var(--text-primary) !important;
}

/* Utils */
.rounded-sm { border-radius: var(--radius-sm); }
.rounded-md { border-radius: var(--radius-md); }
.shadow-sm { box-shadow: var(--shadow-sm); }
.shadow-md { box-shadow: var(--shadow-md); }

/* =====================================================
   Modern Layout Structure - Right Sidebar
   ===================================================== */

/* Right Sidebar */
/* Single source of truth for the docked sidebar width so the content offset
   always matches the rendered sidebar exactly (no gap). Narrower on wide
   screens; the minimized rail and bottom bar override the width below. */
:root { --dock-w: var(--sidebar-width); }
@media (min-width: 1200px) { :root { --dock-w: calc(var(--sidebar-width) * 0.92); } }

.app-sidebar {
  position: fixed;
  top: 0;
  left: 0;
  right: auto;
  width: var(--dock-w);
  height: 100vh;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border-dark);
  border-left: none;
  display: flex;
  flex-direction: column;
  z-index: 1000;
  transition: transform var(--transition-base);
}

.app-sidebar-left {
  left: 0;
  right: auto;
  border-right: 1px solid var(--border-dark);
  border-left: none;
}

.app-sidebar-right {
  left: auto;
  right: 0;
  border-left: 1px solid var(--border-dark);
  border-right: none;
  /* Sit above page content so the dock arrows + width toggle at the bottom are
     never obscured by a sticky widget (e.g. the home calendar) in the column
     beside it. */
  z-index: 1100;
}

/* The floating calendar launcher (.calendar-widget-btn) is fixed bottom-right
   by default and overlaps the dock arrows / +- buttons when the menu is docked
   to the right or bottom. Shift it clear of the dock in those positions.
   Right-dock only: gated to the desktop rail breakpoint, or a right-docked
   sidebar that's gone off-canvas (992px down to the 576px mobile override)
   still shifts the FAB left into the page with nothing left to dodge. */
@media (min-width: 992px) {
  body:has(#sidebar-root.app-sidebar-right) .calendar-widget-btn {
    right: calc(var(--sidebar-width) + 30px);
  }
}

body:has(#sidebar-root.app-sidebar-bottom) .calendar-widget-btn {
  bottom: calc(var(--bottom-nav-height, 64px) + 30px);
}

/* The "Take a tour" launcher sits in the bottom-left corner. The left- and
   bottom-docked sidebar both reach that corner, so it shifts clear of the menu
   in those positions (right dock never touches the left edge). */
.tour-launch-btn {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 2002; /* above the docked sidebar + calendar FAB */
}

body:has(#sidebar-root.app-sidebar-left) .tour-launch-btn {
  left: calc(var(--sidebar-width) + 16px);
}

body:has(#sidebar-root.app-sidebar-bottom) .tour-launch-btn {
  bottom: calc(var(--bottom-nav-height, 64px) + 16px);
}

/* Bottom dock: the menu becomes a horizontal bar across the bottom of the
   viewport (mirrors the old standalone bottom-nav, now folded into one menu). */
.app-sidebar-bottom {
  top: auto;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: auto;
  flex-direction: row;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xs) var(--space-md) calc(var(--space-xs) + env(safe-area-inset-bottom));
  border-right: none;
  border-left: none;
  border-top: 1px solid var(--border-dark);
  box-shadow: 0 -12px 28px rgba(15, 23, 42, 0.12);
  overflow-x: auto;
}

/* In bottom mode the profile card, More overflow and install banner are
   hidden; theme/language/notification controls move inline into the bar
   alongside the primary nav and dock arrows. */
.app-sidebar-bottom .user-profile-card,
.app-sidebar-bottom .sidebar-mode-badge,
.app-sidebar-bottom .pwa-install-banner,
.app-sidebar-bottom .sidebar-nav-secondary .nav-separator {
  display: none;
}

/* In the bottom bar: More sits at the far left and the primary destinations
   keep the rest of the rail compact. */
.app-sidebar-bottom .nav-item-more {
  order: -1;
}

.app-sidebar-bottom .sidebar-user-section {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  padding: 0;
  border-bottom: none;
}

.app-sidebar-bottom .sidebar-controls {
  padding: 0;
}

/* Docking animates in so switching positions feels smooth, not a hard cut.
   The global prefers-reduced-motion rule neutralises this for those users. */
.app-sidebar-left,
.app-sidebar-right,
.app-sidebar-bottom {
  animation: dock-in var(--transition-base) ease;
}

@keyframes dock-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.app-sidebar-bottom .sidebar-nav {
  display: flex;
  flex: 1;
  /* min-width:0 so this flex child may be narrower than its content. Without
     it the rail sized to the sum of its items (492px on a 390px phone) and
     `html { overflow-x: hidden }` silently clipped whatever did not fit -
     measured: Messages, Communities and Connections rendered entirely
     off-screen and were unreachable, with nothing on screen to suggest they
     existed. */
  min-width: 0;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  gap: var(--space-xs);
  padding: 0;
  /* Scroll instead of clip. Touch targets stay at the 44px floor rather than
     shrinking to fit an arbitrary number of destinations. */
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.app-sidebar-bottom .sidebar-nav::-webkit-scrollbar {
  display: none;
}

/* Items keep their width in the scroller instead of being squeezed. */
.app-sidebar-bottom .sidebar-nav > .nav-item,
.app-sidebar-bottom .sidebar-nav > .nav-item-more {
  flex: 0 0 auto;
}

/* When everything does fit, spread it out again rather than bunching left. */
@media (min-width: 600px) {
  .app-sidebar-bottom .sidebar-nav {
    justify-content: space-around;
  }
}

.app-sidebar-bottom .sidebar-nav-secondary {
  display: flex;
  flex: 0 0 auto;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  margin-bottom: 0;
}

/* The divider after Create is meaningless in the horizontal bar. */
.app-sidebar-bottom .sidebar-nav .nav-separator {
  display: none;
}

.app-sidebar-bottom .nav-item {
  flex-direction: column;
  gap: 2px;
  width: auto;
  min-width: 56px;
  padding: var(--space-xs);
  font-size: var(--font-size-xs);
  text-align: center;
}

.app-sidebar-bottom .nav-item.active::before {
  display: none;
}

.app-sidebar-bottom .sidebar-dock-toggle {
  margin: 0;
}

/* Content offset follows the dock side. #sidebar-root is the element
   immediately before .app-content. */
.app-sidebar-right + .app-content {
  margin-left: 0;
  margin-right: var(--dock-w);
}

.app-sidebar-right.minimized + .app-content {
  margin-left: 0;
  margin-right: 60px;
}

.app-sidebar-bottom + .app-content {
  margin-left: 0;
  margin-right: 0;
  padding-bottom: calc(var(--bottom-nav-height, 64px) + env(safe-area-inset-bottom));
}


/* Sidebar Toggle Button */
.sidebar-toggle-btn {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  border: 1px solid var(--border-medium);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all var(--transition-fast);
  z-index: 10;
  font-size: 0.75rem;
}

.sidebar-toggle-btn:hover {
  background: var(--surface-light);
  color: var(--text-primary);
  border-color: var(--craft-indigo);
}

/* Minimized Sidebar State */
  .app-sidebar.minimized {
    width: 60px;
    min-width: 0;
  }

.app-sidebar.minimized .sidebar-user-section,
.app-sidebar.minimized .nav-item span,
.app-sidebar.minimized .nav-badge,
.app-sidebar.minimized .user-profile-info,
.app-sidebar.minimized .user-dropdown-icon {
  display: none;
}

.app-sidebar.minimized .sidebar-controls {
  flex-direction: column;
  padding: var(--space-xs);
}

.app-sidebar.minimized .control-btn {
  width: 36px;
  height: 36px;
}

.app-sidebar.minimized .nav-item {
  justify-content: center;
  padding: var(--space-md);
}

.app-sidebar.minimized .nav-item i {
  margin: 0;
  font-size: 1.25rem;
}

.app-sidebar.minimized .nav-separator {
  margin: var(--space-sm);
}

.app-sidebar.minimized .sidebar-toggle-btn {
  position: relative;
  top: 0;
  right: 0;
  margin: var(--space-sm) auto;
}

/* Left dock only — a right-docked minimized sidebar must NOT get a left margin
   (that left an empty strip beside the header). Right/bottom have their own rules. */
.app-sidebar-left.minimized + .app-content {
  margin-left: 60px;
}

/* Sidebar Navigation */
.sidebar-nav {
  flex: 1;
  padding: var(--space-md) 0;
  overflow-y: auto;
}

.sidebar-nav::-webkit-scrollbar {
  width: 4px;
}

.sidebar-nav::-webkit-scrollbar-thumb {
  background: var(--border-medium);
  border-radius: var(--radius-full);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  color: var(--text-tertiary);
  font-size: var(--font-size-sm);
  font-weight: 500;
  text-decoration: none;
  transition: all var(--transition-fast);
  cursor: pointer;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  position: relative;
}

.nav-item i {
  width: 20px;
  text-align: center;
  font-size: 1.1rem;
  transition: color var(--transition-fast);
}

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

.nav-item:hover i {
  color: var(--craft-indigo);
}

.nav-item.active {
  color: var(--text-primary);
  background: linear-gradient(270deg, var(--craft-indigo-tint) 0%, transparent 100%);
}

.nav-item.active::before {
  content: '';
  position: absolute;
  right: 0;
  left: auto;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 60%;
  background: var(--craft-indigo);
  border-radius: var(--radius-xs) 0 0 var(--radius-xs);
  box-shadow: -1px 0 3px rgba(15, 23, 42, 0.18);
}

.nav-item.active i {
  color: var(--craft-indigo);
  transform: scale(1.12);
}

.nav-separator {
  height: 1px;
  background: var(--border-dark);
  margin: var(--space-md) var(--space-lg);
}

/* Layout-controls footer (dock arrows + width toggle). Unlike .sidebar-nav it
   does NOT grow, so the flex:1 primary nav pushes it down; margin-bottom keeps
   it lifted off the very bottom edge rather than sitting flush. */
.sidebar-nav-secondary {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding-top: var(--space-sm);
  margin-bottom: var(--space-md);
}

/* Sidebar Footer */
.sidebar-footer {
  padding: var(--space-md) var(--space-lg);
  border-top: 1px solid var(--border-dark);
}

.logout-btn {
  color: var(--accent-red) !important;
}

.logout-btn:hover {
  background: rgba(220, 53, 69, 0.1) !important;
  color: var(--accent-red) !important;
}

/* Language Switcher */
.language-switcher {
  margin-top: var(--space-sm);
}

.lang-btn {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--bg-tertiary);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: var(--font-size-xs);
  font-weight: 500;
  cursor: pointer;
  width: 100%;
  transition: all var(--transition-fast);
}

.lang-btn:hover {
  background: var(--surface-light);
  color: var(--text-primary);
}

.lang-btn i {
  font-size: 0.875rem;
}

/* Nav Badge */
.nav-badge {
  font-size: 0.625rem;
  padding: 0.125rem 0.375rem;
  background: var(--craft-indigo);
  color: var(--accent-contrast, #0E2233);
  border-radius: 4px;
  margin-left: auto;
  font-weight: 700;
}

.collab-toggle.active {
  background: rgba(251, 191, 36, 0.1);
  border-color: rgba(251, 191, 36, 0.3);
}

.collab-toggle.active i {
  color: #fbbf24;
}

/* Sidebar User Section */
.sidebar-user-section {
  padding: var(--space-md);
  border-bottom: 1px solid var(--border-dark);
}

.user-profile-card {
  margin-bottom: var(--space-md);
}

.user-profile-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm);
  background: transparent;
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: all var(--transition-fast);
  color: var(--text-primary);
}

.user-profile-btn:hover {
  background: var(--surface-light);
  border-color: var(--craft-indigo);
}

.sidebar-avatar,
.sidebar-avatar-placeholder {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  object-fit: cover;
  object-position: center;
  background: var(--bg-primary);
  flex-shrink: 0;
}

.sidebar-avatar-placeholder {
  background: linear-gradient(135deg, var(--craft-indigo), var(--accent-purple));
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 1rem;
}

.user-profile-info {
  flex: 1;
  text-align: left;
  min-width: 0;
}

.user-profile-name {
  font-weight: 600;
  font-size: var(--font-size-sm);
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.user-profile-status {
  font-size: var(--font-size-xs);
  /* "Online" is a presence state, not brand accent, and it sits beside the
     presence dot - both read from the same token so they cannot disagree. */
  color: var(--color-success);
  font-weight: 500;
}

.user-dropdown-icon {
  color: var(--text-muted);
  font-size: 0.75rem;
  transition: transform var(--transition-fast);
}

.user-profile-btn[aria-expanded="true"] .user-dropdown-icon {
  transform: rotate(180deg);
}

/* Sidebar Controls */
.sidebar-controls {
  display: flex;
  gap: var(--space-sm);
  justify-content: center;
  padding: var(--space-sm) 0;
}

.control-btn {
  position: relative;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--bg-card);
  border: 1px solid var(--border-medium);
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all var(--transition-fast);
  font-size: 1rem;
  text-decoration: none;
}

.control-btn:hover {
  background: var(--surface-highlight);
  color: var(--text-primary);
  border-color: var(--border-light);
}

.control-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 16px;
  height: 16px;
  background: var(--accent-red);
  color: white;
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  border: 2px solid var(--bg-secondary);
}

/* Guest controls (non-authenticated users) */
.sidebar-controls-guest {
  margin: var(--space-md);
  padding: var(--space-sm);
  background: var(--bg-card);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-dark);
}

/* Main Content Area */
.app-content {
  margin-left: var(--dock-w);
  margin-right: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-primary);
  --topbar-min-height: 72px;
}

/* Top Bar */
.top-bar {
  position: sticky;
  top: 0;
  z-index: 900;
  min-height: var(--topbar-min-height);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-dark);
  padding: var(--space-md) var(--space-xl);
  display: flex;
  align-items: center;
  gap: var(--space-lg);
}

.top-nav-controls {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  flex: 0 0 auto;
}

.top-nav-icon-btn,
.top-nav-language-select {
  min-width: 40px;
  min-height: 40px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-medium);
  background: var(--bg-card);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}

.top-nav-icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.top-nav-icon-btn:hover,
.top-nav-language-select:hover {
  background: var(--surface-highlight);
  border-color: var(--border-light);
  color: var(--craft-indigo);
}

.top-nav-icon-btn .badge-dot {
  position: absolute;
  top: 7px;
  right: 7px;
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  background: var(--accent-red);
  border: 2px solid var(--bg-card);
}

.top-nav-icon-btn .nav-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-full);
  background: var(--accent-red);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 800;
  line-height: 18px;
  text-align: center;
}

.top-nav-language-form {
  display: inline-flex;
  align-items: center;
  margin: 0;
}

.top-nav-language-select {
  padding: 0 0.55rem;
  font: inherit;
  font-size: 0.78rem;
  font-weight: 800;
  line-height: 1;
  cursor: pointer;
  appearance: none;
  text-align: center;
}

.top-nav-theme-icon--sun {
  display: none;
}

body.dark-mode .top-nav-theme-icon--moon {
  display: none;
}

body.dark-mode .top-nav-theme-icon--sun {
  display: block;
}

/* Top Bar Brand */
.top-bar-brand {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  color: var(--text-primary);
  font-size: var(--font-size-xl);
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
}

.top-bar-brand:hover {
  color: var(--text-primary);
}

.top-bar-brand i {
  color: var(--craft-indigo);
  font-size: 1.5rem;
}

/* Search Container */
.search-container {
  flex: 1;
  max-width: 100%;
}

.search-form {
  position: relative;
  display: flex;
  align-items: center;
  background: var(--bg-input);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius-full);
  overflow: hidden;
  transition: all var(--transition-fast);
}

.search-form:focus-within {
  border-color: var(--craft-indigo);
  box-shadow: 0 0 0 3px var(--craft-indigo-tint);
}

.search-input {
  flex: 1;
  padding: var(--space-md) var(--space-lg) !important;
  padding-left: 88px !important;
  background: transparent !important;
  border: none !important;
  -webkit-appearance: none;
  appearance: none;
  color: var(--text-primary) !important;
  font-size: var(--font-size-sm);
  border-radius: 0 !important;
  min-width: 0;
}

.search-input::placeholder {
  color: var(--text-placeholder) !important;
}

.search-input:focus {
  /* Same 1.4.11 problem as the global :focus-visible rule below — the brand
     accent is 1.60:1 on white for the default palette. Use --focus-ring. */
  outline: 2px solid var(--focus-ring, #17703D) !important;
  outline-offset: 2px;
  box-shadow: none !important;
}

.search-icon {
  position: absolute;
  top: 50%;
  left: var(--space-lg);
  transform: translateY(-50%);
  color: var(--text-muted);
  font-size: 0.9rem;
  pointer-events: none;
  z-index: 1;
}

[dir="rtl"] .search-input {
  padding-left: var(--space-lg) !important;
  padding-right: 88px !important;
}

[dir="rtl"] .search-icon {
  left: auto;
  right: var(--space-lg);
}

/* Remove native search field decorations that overlap the custom icon */
.search-input::-webkit-search-decoration,
.search-input::-webkit-search-cancel-button,
.search-input::-webkit-search-results-button,
.search-input::-webkit-search-results-decoration {
  display: none;
}

.search-btn {
  padding: var(--space-md) var(--space-xl);
  background: var(--craft-indigo);
  color: var(--accent-contrast, #0E2233);
  border: none;
  font-weight: 600;
  font-size: var(--font-size-sm);
  cursor: pointer;
  transition: all var(--transition-fast);
  white-space: nowrap;
  flex-shrink: 0;
}

.search-btn:hover {
  background: var(--craft-indigo-hover);
}

.search-advanced-btn {
  padding: var(--space-md) var(--space-xl);
  background: var(--bg-card);
  color: var(--text-primary);
  font-weight: 600;
  font-size: var(--font-size-sm);
  text-decoration: none;
  transition: all var(--transition-fast);
  white-space: nowrap;
  border-left: 1px solid var(--border-medium);
  flex-shrink: 0;
  border-top-right-radius: var(--radius-full);
  border-bottom-right-radius: var(--radius-full);
}

.search-advanced-btn:hover {
  background: var(--surface-highlight);
  color: var(--craft-indigo);
}

/* Top Bar Actions (legacy - kept for compatibility) */
.top-bar-actions {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.icon-btn {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--bg-card);
  border: 1px solid var(--border-medium);
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all var(--transition-fast);
  text-decoration: none;
  position: relative;
}

.icon-btn:hover {
  background: var(--surface-highlight);
  color: var(--text-primary);
  border-color: var(--border-light);
}

.icon-btn .badge-dot {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 10px;
  height: 10px;
  background: var(--accent-red);
  border-radius: var(--radius-full);
  border: 2px solid var(--bg-card);
}

/* User Avatar in Top Bar */
.user-avatar {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  object-fit: cover;
  border: 2px solid var(--border-medium);
  cursor: pointer;
  transition: border-color var(--transition-fast);
}

.user-avatar:hover {
  border-color: var(--craft-indigo);
}

.user-avatar-placeholder {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: linear-gradient(135deg, var(--craft-indigo) 0%, var(--accent-purple) 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
}

/* Hide old top elements */
.top-logo-bar,
.search-bar-container {
  display: none !important;
}

/* Main Content */
.main-content {
  flex: 1;
  padding: var(--space-xl);
  max-width: var(--content-max-width);
  margin: 0 auto;
  width: 100%;
}

/* Full-bleed pages (auth two-column layout, profile cover banner) need to reach
   the content edges. The centered max-width column + padding above would
   otherwise leave the page background showing as cream bands on each side — a
   child's negative margin can cancel the padding but never the auto-centering
   margins. Release both here; the profile re-caps its body inside .prof-content. */
.main-content:has(.auth-wrapper),
.main-content:has(.prof-page) {
  max-width: none;
  padding: 0;
}

/* Auth pages fill the space between the header and footer via flex (NOT a magic
   100vh-Npx min-height, which drifts from the real chrome heights and leaves a
   page-background gap). The auth-wrapper flexes to fill; the global
   footer{margin-top:3rem} is zeroed here so no cream band shows above it. */
.main-content:has(.auth-wrapper) {
  display: flex;
  flex-direction: column;
}
.main-content:has(.auth-wrapper) + .app-footer {
  margin-top: 0;
}

/* Page Title */
.page-title {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  margin-bottom: var(--space-lg);
  color: var(--text-primary);
}

/* Footer */
.app-footer {
  padding: var(--space-lg) var(--space-xl);
  border-top: 1px solid var(--border-dark);
  background: var(--bg-secondary);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--font-size-sm);
}

/* Footer links read as a comma-separated list: "About Us, Privacy & Cookies".
   Each link is underlined; the comma separators stay plain. */
.app-footer__links {
  margin-bottom: var(--space-sm);
}

.app-footer__links a,
.app-footer__link-button {
  color: var(--craft-indigo);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.app-footer__links a:hover,
.app-footer__link-button:hover {
  color: var(--craft-indigo-hover, var(--craft-indigo));
}

.app-footer__links > *:not(:last-child)::after {
  content: ", ";
  text-decoration: none;
}

/* Hide old navbar elements */
nav.navbar,
.search-bar-wrap,
.top-navbar,
.navbar,
.navbar-expand-lg,
.navbar-dark,
.navbar-collapse,
.navbar-nav,
.navbar-toggler,
.navbar-brand {
  display: none !important;
}

/* Mobile Header */
.mobile-header {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 60px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-dark);
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--space-md);
  z-index: 1001;
}

.mobile-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: 0 0 44px;
  background: none;
  border: none;
  color: var(--text-primary);
  font-size: 1.5rem;
  cursor: pointer;
  padding: var(--space-sm);
}

.mobile-logo {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-width: 0;
  color: var(--text-primary);
  font-weight: 700;
  text-decoration: none;
}

.mobile-logo span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mobile-logo i {
  color: var(--craft-indigo);
}

.mobile-header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  flex: 0 0 auto;
}

.top-nav-controls--mobile {
  display: inline-flex;
  align-items: center;
  flex-flow: row nowrap;
  gap: var(--space-xs);
}

.top-nav-controls--mobile .top-nav-icon-btn,
.top-nav-controls--mobile .top-nav-language-select {
  width: 40px;
  height: 40px;
  min-width: 40px;
  min-height: 40px;
  flex: 0 0 40px;
  box-sizing: border-box;
}

.top-nav-controls--mobile .top-nav-language-form {
  flex: 0 0 40px;
}

.mobile-icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-primary);
  font-size: 1.25rem;
  text-decoration: none;
  background: none;
  border: none;
  padding: var(--space-sm);
  cursor: pointer;
}

.mobile-avatar,
.mobile-avatar-placeholder {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  object-fit: cover;
}

.mobile-avatar-placeholder {
  background: linear-gradient(135deg, var(--craft-indigo), var(--accent-purple));
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.mobile-search-overlay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  min-height: 100dvh;
  padding: calc(60px + var(--space-md)) max(var(--space-md), env(safe-area-inset-left)) calc(var(--space-lg) + env(safe-area-inset-bottom));
  background:
    radial-gradient(circle at 18% 8%, rgba(255, 255, 255, 0.30), transparent 26%),
    linear-gradient(180deg, rgba(246, 241, 228, 0.78), rgba(246, 241, 228, 0.52));
  backdrop-filter: blur(22px) saturate(1.45);
  -webkit-backdrop-filter: blur(22px) saturate(1.45);
  border-bottom: 1px solid rgba(255, 255, 255, 0.42);
  box-shadow: 0 22px 60px rgba(8, 22, 40, 0.22);
  z-index: 1002;
  overflow-y: auto;
}

.mobile-search-overlay.show {
  display: block;
}

/* NoiseBackground island (#bg-noise-root): a fixed -z-10 layer (brand midnight
   #081628 + electric-green light source + film grain). body is transparent so
   it shows behind all pages; the island supplies the backdrop colour. */
body {
  background: transparent;
}

/* Fallback backdrop, on the island's own mount point.
   With body transparent, the island is the ONLY thing painting the page. If
   its bundle 404s or the mount throws, the page falls through to the browser
   default - a white page in dark mode. Styling the mount point itself covers
   that: the empty div still paints the correct backdrop, and when the island
   does mount it renders an identical fixed layer inside this one, so nothing
   changes visually.
   Why here and not on `html`: the dark palette is defined on `body.dark-mode`,
   so `html` sits outside its scope and would resolve --bg-primary to the LIGHT
   value - painting cream behind a dark page, i.e. wrong in exactly the case
   the fallback exists for. This element is inside body and inherits correctly
   in both themes, with no token value duplicated. */
#bg-noise-root {
  position: fixed;
  inset: 0;
  z-index: -10;
  background: var(--bg-primary);
}

/* The app content column normally paints var(--bg-primary) across the whole
   viewport, which hid the fixed background on logged-in pages. Make it
   transparent so the island shows through there too. Cards/widgets keep their
   own surfaces. */
.app-content {
  background: transparent;
}

/* All chrome (top-bar, footer, mobile) keeps its native token-driven surfaces —
   opaque and theme-correct; the animated background shows through the
   transparent .app-content gaps. No glass hacks, no hardcoded hex, no token
   re-definitions. */

/* Dock/sidebar: brand "cream daytime section" in light (#F6F1E4), midnight in
   dark — via the theme token, so its text stays readable in both. Overrides the
   base .app-sidebar var(--bg-secondary) by cascade order (same specificity). */
.app-sidebar {
  background: var(--bg-primary);
}

.mobile-search-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  max-width: 640px;
  margin: 0 auto var(--space-lg);
}

.mobile-search-title {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  color: var(--text-primary);
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 6vw, 2rem);
  font-weight: 700;
  line-height: 1;
}

.mobile-search-title svg {
  width: 28px;
  height: 28px;
  color: var(--text-muted);
  flex: 0 0 auto;
}

.mobile-search-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: rgba(255, 255, 255, 0.26);
  border: 1px solid rgba(14, 34, 51, 0.12);
  color: var(--text-primary);
  border-radius: var(--radius-full);
  cursor: pointer;
  box-shadow: var(--glass-inset), 0 8px 22px rgba(8, 22, 40, 0.12);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.mobile-search-close:hover {
  background: rgba(255, 255, 255, 0.42);
}

.mobile-search-overlay .search-form {
  max-width: 640px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-sm);
  padding: var(--space-md);
  background: rgba(255, 255, 255, 0.40);
  border: 1px solid rgba(255, 255, 255, 0.56);
  border-radius: 28px;
  overflow: visible;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.58),
    inset 0 -18px 34px rgba(255, 255, 255, 0.16),
    0 18px 44px rgba(8, 22, 40, 0.16);
  backdrop-filter: blur(24px) saturate(1.5);
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
}

.mobile-search-overlay .search-form:focus-within {
  border-color: var(--craft-indigo);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.64),
    inset 0 -18px 34px rgba(255, 255, 255, 0.16),
    0 0 0 3px var(--craft-indigo-tint),
    0 22px 54px rgba(8, 22, 40, 0.18);
}

.mobile-search-overlay .search-icon {
  top: calc(var(--space-md) + 27px);
  left: calc(var(--space-md) + var(--space-md));
  color: var(--text-muted);
}

.mobile-search-overlay .search-input {
  width: 100%;
  min-height: 54px;
  padding: 0 var(--space-md) 0 3.25rem !important;
  background: rgba(255, 255, 255, 0.48) !important;
  border: 1px solid rgba(14, 34, 51, 0.13) !important;
  border-radius: 18px !important;
  font-size: 1rem;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.62);
}

.mobile-search-overlay .search-input:focus {
  outline: none !important;
  border-color: var(--craft-indigo) !important;
  box-shadow: 0 0 0 3px var(--craft-indigo-tint) !important;
}

.mobile-search-overlay .search-btn,
.mobile-search-overlay .search-advanced-btn {
  min-height: 52px;
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 18px;
  font-size: 1rem;
  font-weight: 800;
  border: 1px solid transparent;
}

.mobile-search-overlay .search-btn {
  background: linear-gradient(135deg, var(--craft-indigo), var(--craft-indigo-hover));
  box-shadow: var(--glass-inset), var(--shadow-tinted-lg);
}

.mobile-search-overlay .search-advanced-btn {
  background: rgba(255, 255, 255, 0.30);
  color: var(--text-primary);
  border-color: rgba(14, 34, 51, 0.12);
  box-shadow: var(--glass-inset);
}

body.no-scroll {
  overflow: hidden;
}

@media (max-width: 575.98px) {
  .mobile-search-overlay .search-form {
    border-radius: 24px;
  }
}

[dir="rtl"] .mobile-search-overlay .search-icon {
  left: auto;
  right: calc(var(--space-md) + var(--space-md));
}

[dir="rtl"] .mobile-search-overlay .search-input {
  padding-left: var(--space-md) !important;
  padding-right: 3.25rem !important;
}

[data-theme="dark"] .mobile-search-overlay,
body.dark-mode .mobile-search-overlay {
  background:
    radial-gradient(circle at 18% 8%, var(--accent-blue-glow), transparent 30%),
    linear-gradient(180deg, rgba(8, 22, 40, 0.84), rgba(8, 22, 40, 0.68));
  border-bottom-color: rgba(255, 255, 255, 0.14);
}

[data-theme="dark"] .mobile-search-overlay .search-form,
body.dark-mode .mobile-search-overlay .search-form {
  background: rgba(8, 22, 40, 0.52);
  border-color: rgba(255, 255, 255, 0.16);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -18px 34px rgba(0, 0, 0, 0.14),
    0 22px 54px rgba(0, 0, 0, 0.34);
}

[data-theme="dark"] .mobile-search-overlay .search-input,
body.dark-mode .mobile-search-overlay .search-input {
  background: rgba(255, 255, 255, 0.10) !important;
  border-color: rgba(255, 255, 255, 0.16) !important;
}

[data-theme="dark"] .mobile-search-close,
body.dark-mode .mobile-search-close,
[data-theme="dark"] .mobile-search-overlay .search-advanced-btn,
body.dark-mode .mobile-search-overlay .search-advanced-btn {
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.18);
}

@media (min-width: 992px) {
  .mobile-search-overlay {
    display: none !important;
  }
}

/* =====================================================
   Responsive Design
   ===================================================== */
@media (max-width: 991.98px) {
  .mobile-header {
    direction: ltr;
    display: flex !important;
  }

  body.sidebar-dock-left .mobile-menu-toggle {
    order: -2;
  }

  body.sidebar-dock-left .mobile-logo {
    order: -1;
  }

  body.sidebar-dock-left .mobile-header-actions {
    margin-left: auto;
  }

  body.sidebar-dock-right .mobile-logo,
  body.sidebar-dock-bottom .mobile-logo {
    order: -2;
  }

  body.sidebar-dock-right .mobile-header-actions,
  body.sidebar-dock-bottom .mobile-header-actions {
    margin-left: auto;
  }

  body.sidebar-dock-right .mobile-menu-toggle {
    order: 2;
    margin-left: var(--space-xs);
  }

  body.sidebar-dock-bottom .mobile-menu-toggle {
    display: none;
  }

  .app-content {
    --topbar-min-height: 60px;
  }

  .app-sidebar {
    /* left-anchored (left: 0), so hide off-screen left; translateX(100%)
       would shift it right by its own width and leave it visible */
    transform: translateX(-100%);
    width: 50vw;
    max-width: 180px;
    min-width: 0;
    top: var(--topbar-height);
    height: calc(100vh - var(--topbar-height));
    z-index: 1100;
  }

  .app-sidebar-left {
    left: 0;
    right: auto;
    transform: translateX(-100%);
  }

  .app-sidebar-right {
    left: auto;
    right: 0;
    transform: translateX(100%);
  }

  .app-sidebar.show {
    transform: translateX(0);
    box-shadow: var(--shadow-xl);
  }

  /* Bottom dock is always visible on mobile — it is not a slide-in drawer. */
  .app-sidebar.app-sidebar-bottom {
    transform: none;
    top: auto;
    bottom: 0;
    width: 100%;
    max-width: none;
    height: auto;
    z-index: 1001;
  }

  .app-content {
    margin-left: 0;
    padding-top: 60px;
  }

  .app-sidebar-bottom + .app-content {
    padding-bottom: calc(var(--bottom-nav-height, 64px) + env(safe-area-inset-bottom));
  }

  .main-content {
    padding: var(--space-md);
  }

  .top-bar {
    display: none;
  }

  .sidebar-nav {
    padding-bottom: 120px;
  }

  /* ---- Mobile dock hardening ----
     The width + dock-position toggles are desktop-only affordances. On a phone
     they overflowed the bottom bar (clipping nav items and trapping the user
     off-screen) and the minimize toggle was what closed the drawer. Drop them
     on mobile — every dock position is a self-sufficient layout without them. */
  .app-sidebar .sidebar-nav-secondary {
    display: none;
  }

  .app-sidebar-right + .app-content,
  .app-sidebar-right.minimized + .app-content {
    margin-right: 0;
  }

  /* Bottom dock: equal-width columns that divide the viewport exactly, so the
     destinations + More fit with no horizontal scroll or clipping. The inline
     rail controls (theme / notifications / language) move into the More menu. */
  .app-sidebar-bottom .sidebar-user-section,
  .app-sidebar-bottom .sidebar-controls {
    display: none;
  }

  .app-sidebar.app-sidebar-bottom {
    overflow-x: hidden;
    /* The bar is server-rendered as app-sidebar-left (drawer-hidden at
       translateX(-100%)); without this the base `transition: transform` slides
       it across the whole screen when React switches it to bottom. The dock-in
       keyframes still provide a subtle vertical entrance. */
    transition: none;
  }

  .app-sidebar-bottom .sidebar-nav {
    justify-content: space-between;
    gap: 0;
  }

  .app-sidebar-bottom .nav-item {
    flex: 1 1 0;
    min-width: 0;
    padding: var(--space-xs) 2px;
  }

  .app-sidebar-bottom .nav-item span {
    font-size: 10px;
    line-height: 1.15;
    white-space: nowrap;
  }
}

@media (max-width: 767px) {
  .icon-btn,
  .mobile-icon-btn,
  .mobile-menu-toggle,
  .mobile-search-close {
    min-height: 44px;
    min-width: 44px;
  }
}

@media (min-width: 992px) {
  .mobile-header {
    display: none !important;
  }

  .app-sidebar {
    transform: translateX(0);
  }
}

@media (max-width: 575.98px) {
  .main-content {
    padding: var(--space-sm);
  }

  /* Tighter cards on small screens for consistent sizing */
  .card {
    border-radius: 12px;
    margin-bottom: var(--space-sm);
  }

  .card > .card-body {
    padding: var(--space-md);
  }

  .card > .card-header,
  .card > .card-footer {
    padding: var(--space-sm) var(--space-md);
  }
}

/* =====================================================
   Animation Utilities
   ===================================================== */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.animate-fade-in {
  animation: fadeIn 0.3s ease-out;
}

.animate-slide-up {
  animation: slideUp 0.4s ease-out;
}

/* =====================================================
   Accessibility
   ===================================================== */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* The brand accent is not a legal focus indicator. --craft-indigo is 1.60:1 on
   white and 1.42:1 on Cream for the default palette (also 1.83 sunbeam, 2.74
   terracotta), all under the 3:1 SC 1.4.11 floor. --focus-ring is the token that
   exists for exactly this and is measured against all 52 surfaces, so use it here
   as the [data-btn] and .ds-disclosure rules already do. */
:focus-visible {
  outline: 2px solid var(--focus-ring, #17703D);
  outline-offset: var(--focus-ring-offset, 2px);
}

/* =====================================================
   Perpetual Micro-Interactions (Premium Motion)
   ===================================================== */
@keyframes pulse-premium {
  0%, 100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.85;
    transform: scale(1.02);
  }
}

@keyframes float-gentle {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-2px);
  }
}

@keyframes shimmer-loading {
  0% {
    background-position: -1000px 0;
  }
  100% {
    background-position: 1000px 0;
  }
}

@keyframes glow-pulse {
  0%, 100% {
    box-shadow: none;
  }
  50% {
    box-shadow: none;
  }
}

@keyframes parallax-bg {
  0% { background-position: center 0; }
  100% { background-position: center 100%; }
}

/* =====================================================
   Advanced Motion Features (Magnetic Hover, Pulse, Parallax)
   ===================================================== */

/* Magnetic Hover: Smooth transition for button movement */
.btn-primary, .btn-success, .action-btn.action-primary, .action-btn.action-success, .notif-btn-primary {
  transition: transform 120ms cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .btn-primary, .btn-success, .action-btn.action-primary, .action-btn.action-success, .notif-btn-primary {
    will-change: auto;
    transform: none !important;
  }
}

/* Perpetual Pulse on Pending Notifications */
.pulse-pending {
  animation: pulse-premium 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .pulse-pending {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* Scroll-triggered Parallax Hero Background */
.hero-section, .hero, [data-parallax="hero"] {
  background-attachment: fixed;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  transition: background-position 0.15s linear;
}

@media (prefers-reduced-motion: reduce) {
  .hero-section, .hero, [data-parallax="hero"] {
    background-attachment: scroll;
  }
}

/* Shared Element Transitions (Smooth state changes) */
.shared-transition {
  transition: all 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

.shared-transition.entering {
  opacity: 0;
  transform: scale(0.95);
}

.shared-transition.active {
  opacity: 1;
  transform: scale(1);
}

.shared-transition.exiting {
  opacity: 0;
  transform: scale(0.95);
}

/* =====================================================
   Scrollbar Styling
   ===================================================== */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-track {
  background: var(--bg-secondary);
}

::-webkit-scrollbar-thumb {
  background: var(--border-light);
  border-radius: var(--radius-full);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

/* =====================================================
   Section Heading Styles (server-rendered pages)
   Consumes type-scale vars from tokens.css (SSOT).
   ===================================================== */
.section-heading {
  font-family: var(--font-display);
  font-size: var(--text-scale-display-size);
  font-weight: var(--text-scale-display-weight);
  line-height: var(--text-scale-display-leading);
  letter-spacing: var(--text-scale-display-tracking);
  color: var(--text-primary);
  margin-top: 0;
}


.meta-caption {
  font-family: var(--font-body);
  font-size: var(--text-scale-caption-size);
  font-weight: var(--text-scale-caption-weight);
  line-height: var(--text-scale-caption-leading);
  color: var(--text-muted);
}

/* =====================================================
   Liquid-glass button tokens (hand-authored, theme-aware)
   Consumed by .settings-btn* (settings.html) and the React
   GlassButton. Light theme uses SATURATED fills so white
   labels keep WCAG contrast (the dark theme's frosted, low-
   alpha tints turn pastel on a white card and fail). Dark
   theme keeps the translucent glass that reads over the dark
   surface. Outside the gen markers — safe from `make design`.
   ===================================================== */
:root {
  --glass-primary-bg: linear-gradient(135deg, var(--craft-indigo) 0%, var(--craft-indigo-hover) 100%);
  --glass-primary-text: var(--accent-contrast, #0E2233);
  --glass-primary-border: rgba(255,255,255,0.5);
  --glass-primary-shadow: var(--shadow-tinted-md);
  --glass-primary-shadow-hover: var(--shadow-tinted-lg);
  --glass-neutral-bg: rgba(14,34,51,0.05);
  --glass-neutral-border: rgba(14,34,51,0.16);
  --glass-neutral-text: var(--text-primary);
  --glass-neutral-shadow: 0 6px 18px rgba(14,34,51,0.12);
  --glass-neutral-shadow-hover: 0 10px 24px rgba(14,34,51,0.18);
  --glass-danger-bg: linear-gradient(135deg, rgba(220,53,69,0.95) 0%, rgba(190,40,55,0.9) 100%);
  --glass-danger-shadow: 0 6px 18px rgba(220,53,69,0.30);
  --glass-danger-shadow-hover: 0 10px 26px rgba(220,53,69,0.42);
  --glass-outline-bg: rgba(14,34,51,0.03);
  --glass-outline-border: rgba(14,34,51,0.20);
  --glass-inset: inset 0 1px 0 rgba(255,255,255,0.55), inset 0 -2px 6px rgba(0,0,0,0.08);
}

body.dark-mode {
  --glass-primary-bg: linear-gradient(135deg, var(--craft-indigo) 0%, var(--craft-indigo-hover) 100%);
  --glass-primary-text: var(--accent-contrast, #0E2233);
  --glass-primary-border: rgba(255,255,255,0.28);
  --glass-primary-shadow: var(--shadow-tinted-md);
  --glass-primary-shadow-hover: var(--shadow-tinted-lg);
  --glass-neutral-bg: rgba(255,255,255,0.10);
  --glass-neutral-border: rgba(255,255,255,0.22);
  --glass-neutral-text: var(--text-primary);
  --glass-neutral-shadow: 0 6px 18px rgba(0,0,0,0.18);
  --glass-neutral-shadow-hover: 0 10px 24px rgba(0,0,0,0.22);
  --glass-danger-bg: linear-gradient(135deg, rgba(220,53,69,0.55) 0%, rgba(220,53,69,0.4) 100%);
  --glass-danger-shadow: 0 6px 18px rgba(220,53,69,0.35);
  --glass-danger-shadow-hover: 0 10px 26px rgba(220,53,69,0.45);
  --glass-outline-bg: rgba(255,255,255,0.06);
  --glass-outline-border: rgba(255,255,255,0.30);
  --glass-inset: inset 0 1px 0 rgba(255,255,255,0.4), inset 0 -2px 6px rgba(0,0,0,0.15);
}

/* ─────────────────────────────────────────────────────────────────────────
   Accent aliases and semantic status, resolved LAST.

   The accent existed in two forms: --craft-* which every palette in themes.css
   overrides, and a set of aliases (--accent-green, --accent-blue, --focus-ring)
   that no palette ever touched. Anything painted through an alias therefore
   stayed green no matter which colour the user picked - the "Online" label in
   the menu, the focus ring, the settings toggles. The comment beside
   --focus-ring above even says "themes.css overrides per palette"; it never
   did.

   These are defined here, at the end of the last stylesheet base.html loads,
   because the generated :root and body.dark-mode blocks earlier in this file
   would otherwise win on source order. They point at --craft-* rather than at
   a literal, so a palette only has to define its own accent once and every
   alias follows, in both themes.

   Do not move these into the gen: blocks above - scripts/gen_design_tokens.py
   rewrites those from design-tokens.md and would drop them.
   ───────────────────────────────────────────────────────────────────────── */
:root,
body.dark-mode {
  --accent-green: var(--craft-green-text);
  --accent-blue: var(--craft-indigo);
  --focus-ring: var(--craft-green-text);

  /* Presence and success stay green in every palette: a green dot means
     "online" the world over, and recolouring it to the brand accent would make
     it read as decoration. It was previously UNDEFINED, so each caller fell
     back to its own literal - the same "online" dot rendered #22c55e on the
     home feed and #1E8F4E in the menu. One token, one colour. */
  --color-success: #1E8F4E;
}

body.dark-mode {
  /* #1E8F4E is 2.6:1 on the dark surfaces; the lighter green clears AA there. */
  --color-success: #4DD97A;
}

/* ─────────────────────────────────────────────────────────────────────────
   Dark mode was ignoring the chosen palette, and this is why.

   The generated dark token block is scoped to `body.dark-mode`. A palette
   sets its dark accent on the ROOT element
   (:root[data-palette="x"][data-theme="dark"]). Custom properties inherit
   DOWNWARD, so a declaration on <body> shadows the root value for <body> and
   everything inside it - which is the entire page. Measured with the purple
   palette in dark mode: :root resolved --craft-green-text to #C084FC while
   body and every descendant resolved it to #4DD97A, the default green.
   Specificity never entered into it; the two declarations are on different
   elements.

   --craft-green-text is the only token declared in both places, so the repair
   is narrow: publish the dark default on the root, where palettes can out-
   specify it, then stop body from shadowing whatever the root resolved.

   `inherit` on a custom property takes the parent's computed value, so body
   simply adopts the root's - palette value when a palette supplies one, the
   default below when it does not (1 of the 8 palettes has no dark block).
   ───────────────────────────────────────────────────────────────────────── */
:root[data-theme="dark"] {
  /* Same value the generated body.dark-mode block uses - #17703D is 2.64:1 on
     Ink, so dark needs the lightened Forest. Kept in step with design-tokens.md
     (color.dark_overrides.craft-green-text). */
  --craft-green-text: #4DD97A;
}

/* `html body.dark-mode` (0,1,2), not `body.dark-mode` (0,1,1): the island
   bundle ships its own copy of the dark token block (frontend/src/styles/
   tokens.css) and its stylesheet loads after this one, so an equal-specificity
   rule here would lose on source order. The extra element beats it outright,
   whatever the load order ends up being. */
html body.dark-mode {
  --craft-green-text: inherit;
}
