/* Global reset + app shell layout.
   Header / sidebar are fleshed out in Phase 3. This is the base skeleton. */

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

html {
  -webkit-text-size-adjust: 100%;
  font-family: var(--font-sans);
}

body {
  margin: 0;
  min-height: 100vh; min-height: 100dvh;
  background: var(--color-bg);
  color: var(--color-fg);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: var(--font-bold); line-height: var(--leading-tight); }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }
button { font: inherit; cursor: pointer; }

/* Visible focus ring for keyboard users (never removed). */
:focus-visible {
  outline: 2px solid var(--color-ring);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* SVG icon sprite is hidden but its symbols are referenced via <use>. */
.svg-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }

/* App shell scaffold — Phase 3 builds the real header + sidebar here. */
#app { min-height: 100vh; min-height: 100dvh; }

/* Full-screen boot loader shown before JS mounts. */
.app-boot {
  position: fixed; inset: 0;
  display: grid; place-items: center;
  background: var(--color-bg);
  z-index: var(--z-modal);
}
.app-boot__spinner {
  width: 40px; height: 40px; border-radius: var(--radius-full);
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  animation: app-spin 0.8s linear infinite;
}
@keyframes app-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* ── App shell: sidebar + header + main ─────────────────────────────────── */
.app-shell { display: grid; grid-template-columns: var(--sidebar-width) 1fr; min-height: 100vh; min-height: 100dvh;
  transition: grid-template-columns var(--dur-base) var(--ease-in-out); }

.app-sidebar {
  position: sticky; top: 0; align-self: start; height: 100vh; height: 100dvh;
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-4) var(--space-3);
  background: var(--color-surface); border-right: 1px solid var(--color-border);
  /* No overflow-x:hidden here — it would clip the hover flyout submenus, which
     intentionally render past the sidebar's right edge (position:absolute,
     left:100%). Each label already self-clips via .sidebar__link-label's own
     overflow:hidden, so this ancestor-level clip was redundant anyway. */
  /* position:sticky establishes its own stacking context, so a submenu's
     z-index inside only ranks against other sidebar content — it needs the
     SIDEBAR ITSELF elevated above .app-main's content (cards, sticky header)
     or the flyout paints underneath them despite its own high z-index. */
  z-index: var(--z-drawer);
}
.sidebar__brand { position: relative; padding: var(--space-2) var(--space-3) var(--space-4); font-weight: var(--font-bold); }
.sidebar__brand-row { display: flex; align-items: center; gap: var(--space-3); }
/* Default HRlume mark: full wordmark when expanded, icon-only once collapsed
   (toggled purely via [data-sidebar-collapsed] below — see .sidebar__brand-icon
   for the customer-logo case, which has no such toggle since it's one image). */
.sidebar__brand-full { height: 24px; width: auto; object-fit: contain; background: #fff; border-radius: var(--radius-sm); padding: var(--space-1) var(--space-2); }
.sidebar__brand-compact { display: none; width: 32px; height: 32px; object-fit: contain; border-radius: var(--radius-md); }
.sidebar__brand-icon { width: 32px; height: 32px; object-fit: contain; border-radius: var(--radius-md); flex-shrink: 0; }
.sidebar__powered { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); padding-left: var(--space-3); opacity: 0.55; font-size: var(--text-xs); font-weight: var(--font-medium); }
.sidebar__powered img { width: 14px; height: 14px; object-fit: contain; border-radius: 3px; }

/* Identity card at the top of the drawer — link to the signed-in user's own
   profile. Mirrors the header's avatar+name, but this is the only place that
   also shows the role/position on mobile (the header hides __name below
   900px), so it gives the drawer real "who am I" context on its own. */
.sidebar__profile {
  display: flex; align-items: center; gap: var(--space-3);
  margin: var(--space-2) 0 var(--space-4); padding: var(--space-3);
  border-radius: var(--radius-md); border: 1px solid var(--color-border);
  color: inherit; transition: background var(--dur-fast) var(--ease-in-out);
}
.sidebar__profile:hover { background: var(--color-surface-hover); }
.sidebar__profile-info { min-width: 0; display: flex; flex-direction: column; }
.sidebar__profile-name { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar__profile-role { font-size: var(--text-xs); color: var(--color-fg-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar__profile-avatar { position: relative; display: inline-flex; flex-shrink: 0; }
.sidebar__profile-avatar > i {
  position: absolute; right: -1px; bottom: -1px; width: 10px; height: 10px;
  border: 2px solid var(--color-surface); border-radius: var(--radius-full);
  background: var(--color-success);
}
.sidebar__profile-arrow { width: 14px; height: 14px; margin-left: auto; flex-shrink: 0; color: var(--color-fg-subtle); }
.sidebar__section-label {
  padding: 0 var(--space-3); color: var(--color-fg-subtle);
  font-size: 10px; font-weight: var(--font-bold); letter-spacing: .09em; text-transform: uppercase;
}
/* Positioned relative to .sidebar__brand itself (now its parent, not a
   sibling absolutely placed against #sidebar with a guessed pixel offset)
   and vertically centered on that block's own real height — for custom
   branding with a company name + "Powered by HRlume" line under it, that
   naturally lands between the two text rows instead of hugging the very
   top edge above both. */
.sidebar__mobile-close {
  display: none; position: absolute; top: 50%; right: var(--space-4); transform: translateY(-50%);
  width: 38px; height: 38px; place-items: center; border: 1px solid var(--color-border);
  border-radius: var(--radius-md); background: var(--color-surface); color: var(--color-fg-muted);
}
.sidebar__mobile-close .icon { width: 18px; height: 18px; }

.sidebar__nav { display: flex; flex-direction: column; gap: var(--space-1); }
.sidebar__link {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3); border-radius: var(--radius-md);
  color: var(--color-fg-muted); font-size: var(--text-sm); font-weight: var(--font-medium);
  transition: background var(--dur-fast) var(--ease-in-out), color var(--dur-fast) var(--ease-in-out);
  white-space: nowrap;
}
.sidebar__link:hover { background: var(--color-surface-hover); color: var(--color-fg); }
/* 2026-07-13: active state got a left accent bar (same device as the
   pinned-announcement card) instead of relying on the tinted background
   alone to read as "current page" — makes it identifiable at a glance
   rather than just a slightly different fill. */
.sidebar__link.is-active { background: var(--color-primary-soft); color: var(--color-primary); box-shadow: inset 3px 0 0 var(--color-primary); }
.sidebar__link .icon { width: 20px; height: 20px; flex-shrink: 0; }
.sidebar__link-label { overflow: hidden; text-overflow: ellipsis; flex: 1; }
.sidebar__link .sidebar__link-arrow { width: 14px; height: 14px; flex-shrink: 0; margin-left: auto; opacity: 0.6; }

/* Hover flyout submenu (desktop only — see media query below): hovering a nav
   item with sub-destinations (People/Leaves/Recruiting/Documents) reveals a
   panel of direct links, so users can jump straight to a sub-tab instead of
   landing on the hub's default tab first. Pure CSS :hover, no JS state. */
.sidebar__item { position: relative; }
.sidebar__submenu {
  display: none;
  position: absolute; left: calc(100% + var(--space-2)); top: 0; z-index: var(--z-drawer);
  min-width: 200px; padding: var(--space-1);
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
.sidebar__submenu-link {
  display: block; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  color: var(--color-fg); font-size: var(--text-sm); font-weight: var(--font-medium); white-space: nowrap;
}
.sidebar__submenu-link:hover { background: var(--color-surface-hover); }
.sidebar__submenu-link.is-active { background: var(--color-primary-soft); color: var(--color-primary); }

/* Flyout only triggers on real hover (desktop) — on touch, tapping the parent
   link just navigates straight to the hub, whose own in-page tab bar already
   exposes every sub-destination the flyout would have offered. */
@media (min-width: 901px) {
  .sidebar__item:hover .sidebar__submenu,
  .sidebar__submenu:hover { display: block; }
}

/* Bottom-pinned group (Налаштування + collapse toggle) — visually separated from the
   main nav list by a divider and pushed to the foot of the sidebar via margin-top:auto. */
.sidebar__bottom { margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--color-border); }
.sidebar__collapse {
  display: flex; align-items: center; gap: var(--space-3); width: 100%; margin-top: var(--space-1);
  padding: var(--space-3); border: 0; border-radius: var(--radius-md); background: transparent;
  color: var(--color-fg-subtle); font-size: var(--text-sm); font-weight: var(--font-medium);
  transition: background var(--dur-fast) var(--ease-in-out), color var(--dur-fast) var(--ease-in-out);
}
.sidebar__collapse:hover { background: var(--color-surface-hover); color: var(--color-fg); }
.sidebar__collapse .icon { width: 20px; height: 20px; flex-shrink: 0; }

/* Mobile-only theme/language pair — moved out of the header (which only shows
   burger/search/bell/avatar there) into the drawer, as one segmented pill
   (same visual device as the auth page's language+theme control). Hidden on
   desktop below, where the header keeps its own copies. */
.sidebar__quick-controls {
  display: flex; align-items: stretch; height: 44px; margin-top: var(--space-1);
  border: 1px solid var(--color-border); border-radius: var(--radius-full);
  overflow: hidden;
}
.sidebar__quick-btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--color-fg-muted);
  font-size: var(--text-xs); font-weight: var(--font-bold); letter-spacing: 0.02em;
  transition: background var(--dur-fast) var(--ease-in-out), color var(--dur-fast) var(--ease-in-out);
}
.sidebar__quick-btn + .sidebar__quick-btn { border-left: 1px solid var(--color-border); }
.sidebar__quick-btn:hover { background: var(--color-surface-hover); color: var(--color-fg); }
.sidebar__quick-btn .icon { width: 18px; height: 18px; }
@media (min-width: 901px) { .sidebar__quick-controls { display: none; } }

/* Android app version + update badge (window.HRLUME_ANDROID_APP_VERSION,
   set by MainActivity — absent on the live web app, so this whole block
   never renders there). Same mobile-only visibility as the pair above. */
.sidebar__app-version {
  display: grid; margin-top: var(--space-2);
  color: var(--color-fg-subtle); font-size: var(--text-xs);
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-surface) 74%, transparent);
  overflow: hidden;
}
.sidebar__update-summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  width: 100%; min-height: 40px; padding: 8px 10px; border: 0; background: transparent;
  color: var(--color-fg-subtle); font: inherit; text-align: left;
}
.sidebar__update-summary:hover { background: var(--color-surface-hover); color: var(--color-fg); }
.sidebar__update-summary-side { display: inline-flex; align-items: center; gap: 5px; }
.sidebar__update-summary .icon { transition: transform var(--dur-base) var(--ease-out); }
.sidebar__app-version.is-expanded .sidebar__update-summary .icon { transform: rotate(180deg); }
.sidebar__update-channel-badge {
  padding: 3px 7px; border-radius: var(--radius-full); background: var(--color-primary-soft);
  color: var(--color-primary); font-size: 10px; font-weight: var(--font-bold); letter-spacing: .02em;
}
.sidebar__update-details {
  display: grid; gap: 7px; max-height: 0; padding: 0 10px; opacity: 0; overflow: hidden;
  transition: max-height 280ms var(--ease-out), padding 280ms var(--ease-out), opacity var(--dur-fast) ease;
}
.sidebar__app-version.is-expanded .sidebar__update-details { max-height: 240px; padding: 0 10px 10px; opacity: 1; }
.sidebar__update-channels {
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px; padding: 2px;
  border-radius: var(--radius-md); background: var(--color-surface-2);
}
.sidebar__update-channel {
  min-height: 28px; border: 0; border-radius: 6px; background: transparent;
  color: var(--color-fg-muted); font: inherit; font-weight: var(--font-semibold);
}
.sidebar__update-channel.is-active {
  background: var(--color-surface); color: var(--color-primary); box-shadow: var(--shadow-xs);
}
.sidebar__update-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 34px;
  padding: var(--space-1) var(--space-3); border: 0; border-radius: var(--radius-md);
  background: var(--color-primary); color: #fff; font-size: var(--text-xs); font-weight: var(--font-bold);
  animation: sidebar-update-pulse 2s ease-in-out infinite;
}
@keyframes sidebar-update-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--color-primary-soft); }
  50% { box-shadow: 0 0 0 5px transparent; }
}
.sidebar__update-check-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 34px;
  padding: var(--space-1) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: transparent; color: var(--color-fg-subtle); font-size: var(--text-xs);
}
.sidebar__update-check-btn:hover { background: var(--color-surface-hover); color: var(--color-fg); }
.sidebar__update-check-btn.is-busy { color: var(--color-primary); background: var(--color-primary-soft); border-color: transparent; }
.sidebar__update-motion { display: none; width: 14px; height: 14px; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent; }
.sidebar__update-check-btn.is-busy .sidebar__update-motion { display: inline-block; animation: sidebar-update-spin .72s linear infinite; }
.sidebar__update-btn .sidebar__update-motion { display: inline-block; border-width: 0; background: currentColor; box-shadow: -4px 0 0 color-mix(in srgb, currentColor 35%, transparent), 4px 0 0 color-mix(in srgb, currentColor 60%, transparent); animation: sidebar-update-orbit 1.1s ease-in-out infinite; }
.sidebar__update-status { color: var(--color-fg-muted); line-height: 1.35; }
@keyframes sidebar-update-spin { to { transform: rotate(360deg); } }
@keyframes sidebar-update-orbit { 0%, 100% { transform: scale(.55); opacity: .7; } 50% { transform: scale(.82); opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .sidebar__update-btn, .sidebar__update-btn .sidebar__update-motion, .sidebar__update-check-btn.is-busy .sidebar__update-motion { animation: none; }
}
@media (min-width: 901px) { .sidebar__app-version { display: none; } }

/* Collapsed state — icon rail only, desktop-only (the mobile drawer already fully
   hides/shows the sidebar via its own .is-open transform, so this is scoped above
   the drawer breakpoint to avoid the two mechanisms fighting each other). */
@media (min-width: 901px) {
  :root[data-sidebar-collapsed] .app-shell { grid-template-columns: var(--sidebar-width-collapsed) 1fr; }
  :root[data-sidebar-collapsed] .sidebar__brand { padding-left: 0; padding-right: 0; }
  :root[data-sidebar-collapsed] .sidebar__brand-row { justify-content: center; }
  :root[data-sidebar-collapsed] .sidebar__brand-full { display: none; }
  :root[data-sidebar-collapsed] .sidebar__brand-compact { display: block; }
  :root[data-sidebar-collapsed] .sidebar__brandname,
  :root[data-sidebar-collapsed] .sidebar__powered,
  :root[data-sidebar-collapsed] .sidebar__section-label,
  :root[data-sidebar-collapsed] .sidebar__link-label,
  :root[data-sidebar-collapsed] .sidebar__link-arrow { display: none; }
  :root[data-sidebar-collapsed] .sidebar__link,
  :root[data-sidebar-collapsed] .sidebar__collapse { justify-content: center; gap: 0; }
  :root[data-sidebar-collapsed] .nav-badge { position: absolute; top: 6px; right: 6px; }
  :root[data-sidebar-collapsed] .sidebar__link { position: relative; }
  :root[data-sidebar-collapsed] .sidebar__profile { justify-content: center; padding: var(--space-2); border-color: transparent; }
  :root[data-sidebar-collapsed] .sidebar__profile-info { display: none; }
  :root[data-sidebar-collapsed] .sidebar__profile-arrow,
  :root[data-sidebar-collapsed] .sidebar__profile-avatar > i { display: none; }
}

.app-main { min-width: 0; display: flex; flex-direction: column; }

.app-placeholder__code { font-size: var(--text-4xl); }
.app-placeholder .btn { text-decoration: none; }

.app-header {
  position: sticky; top: 0; z-index: var(--z-header);
  display: flex; align-items: center; gap: var(--space-4);
  /* env(safe-area-inset-top) is 0 on a normal browser tab/desktop — this
     only does anything inside the Android app, which renders edge-to-edge
     (viewport-fit=cover) behind the status bar. Extends the header's own
     themed background up behind it instead of a plain white gap showing
     through (see HRlume-Android's MainActivity for the native half). */
  min-height: calc(var(--header-height) + var(--safe-area-top));
  padding: 0 var(--space-6); padding-top: var(--safe-area-top);
  background: var(--color-surface); border-bottom: 1px solid var(--color-border);
}
.hdr-icon {
  display: grid; place-items: center; width: 40px; height: 40px; flex-shrink: 0;
  border: 0; border-radius: var(--radius-md); background: transparent; color: var(--color-fg-muted);
}
.hdr-icon:hover { background: var(--color-surface-hover); color: var(--color-fg); }
.hdr-lang { width: auto; padding: 0 var(--space-3); font-size: var(--text-sm); font-weight: var(--font-semibold); }
.hdr-burger { display: none; }

/* 2026-07-13: widened 420px→560px per polish feedback ("ширший пошук") —
   the top bar had a lot of unused space beside it on desktop. */
.hdr-search { position: relative; flex: 1; max-width: 560px; display: flex; align-items: center; }
.hdr-search > .icon { position: absolute; left: var(--space-3); width: 18px; height: 18px; color: var(--color-fg-subtle); pointer-events: none; }
.hdr-search input {
  width: 100%; height: 40px; padding: 0 var(--space-3) 0 var(--space-10);
  font: inherit; font-size: var(--text-sm); color: var(--color-fg);
  background: var(--color-surface-2); border: 1px solid transparent; border-radius: var(--radius-md);
}
.hdr-search input:focus { outline: none; border-color: var(--color-ring); background: var(--color-surface); }

.hdr-actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.hdr-dropdown { position: relative; }
.hdr-user { display: flex; align-items: center; gap: var(--space-2); height: 40px; padding: 0 var(--space-2); border: 0; border-radius: var(--radius-md); background: transparent; color: var(--color-fg); }
.hdr-user:hover { background: var(--color-surface-hover); }
.hdr-user__name { font-size: var(--text-sm); font-weight: var(--font-medium); }
.icon--sm { width: 16px; height: 16px; }

.dropdown-menu {
  position: absolute; top: calc(100% + var(--space-2)); right: 0; min-width: 200px;
  padding: var(--space-1); background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  z-index: var(--z-drawer);
}
.dropdown-menu--right { right: 0; }
.dropdown-item {
  display: flex; align-items: center; width: 100%; min-height: 38px;
  box-sizing: border-box; gap: var(--space-2); padding: 9px var(--space-3);
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--color-fg);
  font: inherit; font-size: var(--text-sm); line-height: 1.25;
  text-align: left; text-decoration: none;
}
.dropdown-item:hover { background: var(--color-surface-hover); }
.dropdown-item--danger { color: var(--color-danger); }
.dropdown-divider { border-top: 1px solid var(--color-border); margin: var(--space-1) 0; }
.dropdown-empty { padding: var(--space-6) var(--space-4); text-align: center; color: var(--color-fg-muted); font-size: var(--text-sm); }

/* Global search results dropdown (Phase 73) — shared by .hdr-search
   (desktop) and .dash-search (mobile), both already position:relative, so
   this just needs to override .dropdown-menu's right-aligned/narrow default. */
.search-results-menu {
  left: 0; right: 0; width: auto; min-width: 0;
  max-height: min(72vh, 560px); overflow-y: auto; padding: 0;
  border-color: var(--color-border-strong); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-xl); overscroll-behavior: contain;
}
.search-result-summary {
  position: sticky; top: 0; z-index: 2; display: flex; align-items: center;
  justify-content: space-between; gap: var(--space-3); padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border); background: color-mix(in srgb, var(--color-surface) 94%, transparent);
  backdrop-filter: blur(12px); font-size: var(--text-xs);
}
.search-result-summary strong { color: var(--color-fg); }
.search-result-summary span { overflow: hidden; color: var(--color-fg-muted); text-overflow: ellipsis; white-space: nowrap; }
.search-result-group {
  --search-group-tone: var(--color-primary);
  position: relative; margin: 0 var(--space-2); padding: var(--space-2) 0 var(--space-2) 9px;
}
.search-result-group::before {
  position: absolute; top: var(--space-3); bottom: var(--space-3); left: 1px; width: 2px;
  border-radius: var(--radius-full); background: color-mix(in srgb, var(--search-group-tone) 52%, var(--color-border)); content: '';
}
.search-result-group + .search-result-group { border-top: 1px solid var(--color-border); }
.search-result-group--people, .search-result-group--teams { --search-group-tone: var(--color-primary); }
.search-result-group--candidates, .search-result-group--jobs { --search-group-tone: var(--color-warning); }
.search-result-group--requests, .search-result-group--goals { --search-group-tone: var(--color-success); }
.search-result-group--documents, .search-result-group--knowledge, .search-result-group--courses { --search-group-tone: var(--color-info, var(--color-primary)); }
.search-result-group--announcements, .search-result-group--surveys { --search-group-tone: var(--color-danger); }
.search-result-group__label {
  display: flex; align-items: center; justify-content: space-between; padding: var(--space-1) var(--space-3);
  font-size: 10px; font-weight: var(--font-bold); text-transform: uppercase;
  letter-spacing: .065em; color: var(--color-fg-subtle);
}
.search-result-group__label b { min-width: 20px; padding: 1px 6px; border-radius: var(--radius-full); background: var(--color-surface-2); color: var(--color-fg-muted); text-align: center; }
.search-result-item {
  display: flex; align-items: center; gap: var(--space-2); width: 100%;
  min-height: 50px; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
  color: var(--color-fg); text-decoration: none; box-sizing: border-box;
}
.search-result-item:hover, .search-result-item.is-active { background: var(--color-surface-hover); }
.search-result-item.is-active { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--search-group-tone) 32%, transparent); }
.search-result-item__icon {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 32px; height: 32px; border-radius: var(--radius-md);
  background: var(--color-surface-2); color: var(--color-fg-muted);
}
.search-result-item__icon .icon { width: 16px; height: 16px; }
.search-result-item__avatar {
  display: inline-flex;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  align-items: center;
  justify-content: center;
}
.search-result-item__avatar .employee-avatar {
  box-shadow: 0 0 0 1px var(--color-border);
}
.search-result-item__text { display: flex; flex-direction: column; min-width: 0; }
.search-result-item__text strong { font-size: var(--text-sm); font-weight: var(--font-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-result-item__text small { font-size: var(--text-xs); color: var(--color-fg-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-result-item__text mark { padding: 0; border-radius: 2px; background: color-mix(in srgb, var(--color-warning) 24%, transparent); color: inherit; font-weight: var(--font-bold); }
.search-result-item__arrow { width: 14px; height: 14px; margin-left: auto; flex: 0 0 14px; color: var(--color-fg-subtle); opacity: 0; transform: translateX(-4px); transition: opacity var(--dur-fast), transform var(--dur-fast); }
.search-result-item:hover .search-result-item__arrow, .search-result-item.is-active .search-result-item__arrow { opacity: 1; transform: none; }
.search-result-help {
  position: sticky; bottom: 0; z-index: 2; display: flex; gap: var(--space-4); padding: 8px var(--space-4);
  border-top: 1px solid var(--color-border); background: color-mix(in srgb, var(--color-surface) 94%, transparent);
  backdrop-filter: blur(12px); color: var(--color-fg-subtle); font-size: 10px;
}
.search-index { padding: var(--space-4); }
.search-index__intro { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.search-index__intro > div { display: grid; min-width: 0; gap: 2px; }
.search-index__intro strong { font-size: var(--text-sm); }
.search-index__intro small { color: var(--color-fg-muted); font-size: var(--text-xs); line-height: 1.4; }
.search-index__mark, .search-state__icon, .search-state__pulse {
  display: grid; place-items: center; width: 38px; height: 38px; flex: 0 0 38px;
  border-radius: 13px; background: var(--color-primary-soft); color: var(--color-primary);
}
.search-index__mark .icon, .search-state__icon .icon, .search-state__pulse .icon { width: 17px; height: 17px; }
.search-quick-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
.search-quick-link {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-2);
  min-height: 44px; padding: var(--space-2); border: 1px solid var(--color-border); border-radius: var(--radius-md);
  color: var(--color-fg); font-size: var(--text-xs); font-weight: var(--font-semibold); text-decoration: none;
}
.search-quick-link:hover { border-color: var(--color-border-strong); background: var(--color-surface-hover); }
.search-quick-link > span { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 9px; background: var(--color-surface-2); color: var(--color-primary); }
.search-quick-link .icon { width: 14px; height: 14px; }
.search-quick-link__arrow { color: var(--color-fg-subtle); }
.search-state { display: flex; align-items: center; justify-content: center; gap: var(--space-3); min-height: 112px; padding: var(--space-5); color: var(--color-fg-muted); }
.search-state > div { display: grid; gap: 2px; }
.search-state strong { color: var(--color-fg); font-size: var(--text-sm); }
.search-state small { font-size: var(--text-xs); }
.search-state--error .search-state__icon { background: var(--color-danger-soft); color: var(--color-danger); }
.search-state__pulse { animation: search-workspace-pulse 1.25s ease-in-out infinite; }
@keyframes search-workspace-pulse { 50% { transform: scale(.92); opacity: .58; } }
@media (prefers-reduced-motion: reduce) { .search-state__pulse { animation: none; } }

/* Notification bell */
.hdr-icon { position: relative; }
.hdr-badge { position: absolute; top: 3px; right: 3px; min-width: 16px; height: 16px; padding: 0 4px; font-size: 10px; line-height: 16px; }
.notif-menu { width: 340px; max-width: 90vw; padding: 0; overflow: hidden; }
/* Mobile: .dropdown-menu--right anchors via `right: 0` against the bell's
   own small wrapper (.hdr-dropdown), not the viewport — on a narrow phone
   the bell isn't flush against the screen edge (avatar/chevron sit after
   it), so a 340px-wide panel anchored there overflowed past the LEFT edge
   of the screen, clipping most of its own content. Same breakpoint the
   header already switches to its mobile layout at. */
@media (max-width: 900px) {
  .notif-menu {
    position: fixed;
    top: calc(var(--header-height) + var(--safe-area-top) + var(--space-2));
    left: var(--space-3); right: var(--space-3);
    width: auto; max-width: none;
  }
}
.notif-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-border); font-weight: var(--font-semibold); font-size: var(--text-sm); }
.notif-readall { border: 0; background: transparent; color: var(--color-primary); font-size: var(--text-xs); font-weight: var(--font-semibold); cursor: pointer; }
#notif-list { max-height: 380px; overflow-y: auto; }
.notif-item { display: grid; width: 100%; grid-template-columns: 34px minmax(0, 1fr) 7px; align-items: center; gap: 10px; text-align: left; padding: var(--space-3) var(--space-4); border: 0; border-bottom: 1px solid var(--color-border); background: transparent; cursor: pointer; }
.notif-item:hover { background: var(--color-surface-hover); }
.notif-item.is-unread { background: var(--color-primary-soft); }
.notif-item__icon { display: grid; width: 34px; height: 34px; place-items: center; border-radius: 10px; color: var(--color-fg-muted); background: var(--color-surface-2); }
.notif-item__icon .icon { width: 16px; height: 16px; }
.notif-item__icon--primary { color: var(--color-primary); background: var(--color-primary-soft); }
.notif-item__icon--success { color: var(--color-success); background: var(--color-success-soft); }
.notif-item__icon--warning { color: var(--color-warning); background: var(--color-warning-soft); }
.notif-item__icon--danger { color: var(--color-danger); background: var(--color-danger-soft); }
.notif-item__copy { display: block; min-width: 0; }
.notif-item__copy > span { display: block; }
.notif-item__unread { width: 7px; height: 7px; border-radius: 50%; background: var(--color-primary); }
.notif-item__title { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-fg); }
.notif-item__body { font-size: var(--text-xs); color: var(--color-fg-muted); margin-top: 2px; }
.notif-item__time { font-size: var(--text-xs); color: var(--color-fg-subtle); margin-top: 2px; }
.notif-viewall { display: block; text-align: center; padding: var(--space-3) var(--space-4); font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-primary); text-decoration: none; border-top: 1px solid var(--color-border); }
.notif-viewall:hover { background: var(--color-surface-hover); }

/* Notifications inbox page (backlog Priority 13) */
.notif-card { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); cursor: pointer; }
.notif-card.is-unread { border-left: 3px solid var(--color-primary); }
.notif-card__main { min-width: 0; flex: 1; }
.notif-card__action { flex-shrink: 0; }

/* Swipe-to-reveal read/delete (touch-only — see notifications.js's own
   setupSwipeActions() for why). .notif-card sits on top of its own action
   row and translates via inline style while dragging; .card's own opaque
   background is what actually hides the actions until it moves. */
.notif-swipe { position: relative; overflow: hidden; border-radius: var(--radius-lg); margin-bottom: var(--space-2); }
.notif-swipe__actions { position: absolute; inset: 0; display: flex; justify-content: flex-end; }
.notif-swipe__action {
  width: 72px; border: none; color: #fff; font-size: var(--text-xs); font-weight: var(--font-semibold); cursor: pointer;
}
.notif-swipe__action--read { background: var(--color-primary); }
.notif-swipe__action--delete { background: var(--color-danger); }
.notif-swipe .notif-card {
  position: relative; z-index: 1; touch-action: pan-y;
  transition: transform var(--dur-base) var(--ease-out);
}

.app-view { flex: 1; width: 100%; max-width: var(--content-max); margin: 0 auto; padding: var(--space-8) var(--space-6); }
/* Per-navigation fade — toggled by app.js's shell() (app-view--enter added
   then removed a frame later, so the transition below actually runs). */
/* Keep headers and section tabs stationary throughout navigation. A transform
   also creates a containing block for fixed descendants during the fade. */
.app-view { opacity: 1; transition: opacity var(--dur-base) var(--ease-out); }
.app-view.app-view--enter { opacity: 0; transition: none; }
@media (prefers-reduced-motion: reduce) {
  .app-view { transition: none; }
  .app-view.app-view--enter { opacity: 1; transform: none; }
}
.sidebar-scrim { display: none; }

/* License status banner (Phase 47) — persistent, not a dismissible toast. */
.license-banner { padding: var(--space-3) var(--space-6); font-size: var(--text-sm); font-weight: var(--font-medium); text-align: center; }
.license-banner--danger { background: var(--color-danger-soft); color: var(--color-danger); }
.license-banner--warn { background: var(--color-warning-soft); color: var(--color-warning); }
/* Phase 48 — read-only (expired, not revoked): deliberately orange, distinct
   from the red (revoked) and amber (stale) banners above. */
.license-banner--readonly { background: var(--color-orange-soft); color: var(--color-orange); }
/* Phase 49 — trial countdown: blue, distinct from every other banner state
   above (none of them mean "everything's fine, just a heads-up"). */
.license-banner--trial { background: var(--color-primary-soft); color: var(--color-primary); }

/* 2026-07-19 — "no license at all" (a freshly provisioned/registered
   instance). Solid primary fill + inline CTA, not another soft/tinted bar
   like the others — this is the one banner state with a single obvious
   next action (paste a key), so it reads as a prompt to act, not a status
   readout. */
.license-banner--none {
  display: flex; align-items: center; justify-content: center; gap: var(--space-3);
  background: var(--color-primary); color: var(--color-on-primary);
}
.license-banner--none .icon { width: 18px; height: 18px; flex-shrink: 0; }
.license-banner__cta {
  display: inline-flex; align-items: center; padding: 3px var(--space-3);
  background: rgba(255, 255, 255, 0.18); color: #fff; border-radius: var(--radius-full);
  font-weight: var(--font-semibold); font-size: var(--text-xs); text-decoration: none;
  transition: background var(--dur-fast) var(--ease-in-out);
}
.license-banner__cta:hover { background: rgba(255, 255, 255, 0.3); }
@media (max-width: 560px) {
  .license-banner--none { flex-wrap: wrap; }
}

/* 2026-08-01 — "connect to License Admin" reminder: same shape as
   --none above (solid fill + inline CTA — this also has one obvious next
   action) but a distinct violet, since blue is already both --primary
   (trial) and --info, and this needs to read as visually different from
   the trial countdown. The one dismissable banner (with confirmation) —
   every other state above is either urgent enough to keep re-showing or
   resolves itself once the admin acts. */
.license-banner--pairing {
  display: flex; align-items: center; justify-content: center; gap: var(--space-3);
  background: #7c3aed; color: #fff;
}
.license-banner--pairing .icon { width: 18px; height: 18px; flex-shrink: 0; }
.license-banner__dismiss {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: var(--radius-full); border: none;
  background: transparent; color: #fff; opacity: .75; cursor: pointer;
  transition: opacity var(--dur-fast) var(--ease-in-out), background var(--dur-fast) var(--ease-in-out);
}
.license-banner__dismiss:hover { opacity: 1; background: rgba(255, 255, 255, 0.18); }
.license-banner__dismiss .icon { width: 14px; height: 14px; }
@media (max-width: 560px) {
  .license-banner--pairing { flex-wrap: wrap; }
}

@media (max-width: 900px) {
  .app-shell { grid-template-columns: 1fr; }
  .app-sidebar {
    position: fixed; left: 0; top: 0; z-index: var(--z-modal);
    /* Was a flat var(--sidebar-width) (264px) — on a 375-430px phone that's
       only ~60-70% of the screen and read as cramped. min(86vw,340px) hits
       the requested ~82-86% on phones while staying a sane drawer width
       (not a second full page) once this breakpoint's upper end (900px)
       is a small tablet. */
    width: min(86vw, 340px);
    transform: translateX(-100%); transition: transform var(--dur-base) var(--ease-out);
    /* The base rule leaves both axes at their default `visible` on purpose —
       desktop's hover flyout submenus (position:absolute, rendered past the
       sidebar's right edge) rely on that. Scoping overflow-y:auto to mobile
       only avoids the CSS "if one axis is auto the other computes to auto
       too" coupling from ever reaching the desktop rule and re-clipping
       those flyouts; the drawer has no flyout to protect, so it's safe here.
       Without this the drawer's content (profile card + growing nav list)
       could exceed 100dvh with no way to reach what's cut off. */
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    /* Same edge-to-edge status-bar treatment as .app-header above — the
       drawer is a full-height fixed overlay reaching top:0 too. */
    padding-top: var(--safe-area-top);
  }
  .app-sidebar.is-open { transform: none; box-shadow: var(--shadow-xl); }
  /* Live drag (native-bootstrap.js's HRlumeOnDrawerDragStart, driven by
     MainActivity's raw touch tracking) — --drawer-drag is the current
     finger distance in CSS px, set once per animation frame. transition:
     none while dragging so it tracks the finger exactly with no lag;
     removing this class (drag-end) lets the base rule's own transition
     animate the final snap to open/closed from wherever the drag left off.
     min() with the drawer's own -100% clamps the open end so a finger that
     overshoots the drawer's actual (responsive, viewport-relative) width
     never drags it past fully open. */
  .app-sidebar.is-dragging {
    transition: none;
    transform: translateX(min(0px, calc(-100% + var(--drawer-drag, 0px))));
  }
  .sidebar__mobile-close { display: grid; }
  .hdr-burger { display: grid; }
  .sidebar-scrim.is-open { display: block; position: fixed; inset: 0; z-index: var(--z-drawer); background: var(--color-overlay); }
  .sidebar-scrim.is-dragging { transition: none; }
  .hdr-user__name { display: none; }
  .sidebar__collapse { display: none; } /* icon-rail collapse is a desktop-only affordance — the drawer already fully hides the sidebar on mobile */
  /* Top bar simplification: theme/language move into the drawer's own
     .sidebar__quick-controls pill (see above) — the header keeps only
     burger · search · bell · avatar. */
  .hdr-theme, .hdr-lang { display: none; }
  /* The compact header search would crowd the mobile top bar; dashboard.js
     renders the same real workspace search at full width below the greeting,
     while the persistent bottom-nav opens its dedicated full-screen view. */
  .hdr-search { display: none; }
  /* Safety net against stray horizontal page-scroll on phones. `clip` (not
     hidden) creates no scroll container and doesn't touch position:sticky; the
     desktop hover flyouts live above 901px, so nothing here is being clipped.
     The real per-component fixes (minmax grids → min(N,100%)) are the primary
     defense; this just guarantees the page can never scroll sideways. */
  .app-view { overflow-x: clip; }
}
@media (max-width: 560px) {
  .app-view { padding: var(--space-5) var(--space-4); }
}

/* Bottom nav (mobile only) — a fixed shortcut bar for the
   destinations actually used daily (Головна/Люди/Відпустки/Пошук);
   the drawer (hamburger button, unaffected by this) still reaches
   everything else. Declared in its own block, after both breakpoints
   above, specifically so this padding-bottom addition (not the `padding`
   shorthand — that would wipe the horizontal/top values either mobile
   block already set) reliably wins at every width ≤900px regardless of
   which of those two blocks last touched .app-view's own padding. */
.bottom-nav { display: none; }
@media (max-width: 900px) {
  /* Extra +10px on top of env(safe-area-inset-bottom) (BOTTOM_NAV_BUFFER_PX,
     matched below in .app-view's own padding) — the raw inset value alone
     left the tab labels sitting right up against Android's system gesture
     pill with barely any breathing room (real user report, screenshot: the
     row read as "too low"), even though nothing was actually overlapping.
     A small fixed buffer is deliberately simpler and more robust here than
     trying to get the exact inset value pixel-perfect. */
  .app-view { padding-bottom: calc(var(--space-6) + 56px + env(safe-area-inset-bottom, 0px) + 10px); }
  .bottom-nav {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-sticky);
    background: var(--color-surface); border-top: 1px solid var(--color-border);
    padding: 0 var(--space-2) calc(env(safe-area-inset-bottom, 0px) + 10px);
    box-shadow: 0 -2px 10px rgba(15, 23, 42, 0.06);
  }
  .bottom-nav__link {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    min-height: 56px; position: relative; z-index: 0;
    color: var(--color-fg-muted); text-decoration: none; font-size: 11px; font-weight: var(--font-medium);
    /* Also used as a <button> (the Search item, which opens an overlay
       instead of navigating) — neutralize UA button chrome so it matches
       the <a> siblings instead of showing a border/background box. */
    border: none; background: none; font-family: inherit; padding: 0; cursor: pointer;
  }
  .bottom-nav__link .icon { width: 22px; height: 22px; stroke-width: 2; }
  .bottom-nav__link span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Color alone was the only signal for the active tab — a real
     color-not-only accessibility gap for anyone with a color-vision
     deficiency. The icon now also gets a bolder stroke and the label a
     heavier weight, so the active state reads even in grayscale. */
  .bottom-nav__link.is-active { color: var(--color-primary); font-weight: var(--font-semibold); }
  .bottom-nav__link.is-active .icon { stroke-width: 2.5; }
  /* Soft pill behind the icon on the active tab, scaling/fading in rather
     than snapping — every item is flex:1 (equal width) so a single ::before
     per link, not a shared cross-item sliding indicator, is enough to read
     as "alive" without any JS position math. */
  .bottom-nav__link::before {
    content: ''; position: absolute; top: 2px; left: 50%; z-index: -1;
    width: 44px; height: 26px; border-radius: var(--radius-full);
    background: var(--color-primary-soft);
    opacity: 0; transform: translate(-50%, 0) scale(0.6);
    transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
  }
  .bottom-nav__link.is-active::before { opacity: 1; transform: translate(-50%, 0) scale(1); }
  .bottom-nav__badge { position: absolute; top: 2px; left: calc(50% + 6px); }
}
