/* ═══════════════════════════════════════════
   MAIN SHELL
═══════════════════════════════════════════ */
.app-frame {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100vh;
  height: 100dvh;
}

.app-shell {
  display: flex;
  flex: 1;
  min-width: 0;
  min-height: 0;
  width: 100%;
}

.main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  height: 100%;
  overflow: hidden;
}

/* Full-width app header: brand lockup, then location (tabs/back-link),
   search, and utility actions. The sidebar sits below this, nav-only. */
.topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 13px 28px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.topbar-search-region {
  display: contents;
}
.topbar-brand {
  display: inline-flex;
  align-items: center;
  border-radius: var(--r-sm);
  flex-shrink: 0;
}
.topbar-brand:focus-visible {
  outline: 2px solid var(--brass-lo);
  outline-offset: 2px;
}
.topbar-brand__image {
  display: block;
  height: 28px;
  width: auto;
  /* .topbar keeps flex-wrap: wrap so .topbar-workspace can break onto its
     own row (below); that same wrap algorithm lines up row 1's items by
     their NATURAL size before any flex-shrink runs, so a shrinkable brand
     doesn't actually stop hamburger+brand+search/bell/+New from wrapping —
     confirmed live at the real 320px floor (this app's CSS min-width). 56px
     is the measured safe cap there: hamburger(44) + search-toggle(44) +
     bell(44) + the collapsed +New button's own 64px floor + this row's
     gaps/padding leave ~57px for the logo before it wraps, at any uploaded
     aspect ratio (object-fit: contain letterboxes rather than distorting a
     wider image, it just renders shorter within this box). */
  max-width: 56px;
  object-fit: contain;
}
/* Desktop only: the brand occupies the sidebar's own column (same width,
   same left indent as a nav-icon — .sidebar-nav's 10px + .nav-item's 12px)
   so the tab/back-link slot right after it lines up with .view-scroll's own
   28px left padding, not just the sidebar's right border. Below the drawer
   breakpoint the sidebar isn't a column to line up with, so the brand just
   sits in the topbar's own padding like every other control. The logo also
   only grows here — at 375px the larger mark was wide enough to push the
   mobile-search/bell/+New cluster onto its own row. */
@media (min-width: 1366px) {
  .topbar {
    padding-left: 0;
  }
  .topbar-brand {
    width: var(--sidebar-w);
    box-sizing: border-box;
    padding-left: 22px;
    /* .topbar's flex `gap` already inserts 14px before the next control;
       this adds the other 14px to match .view-scroll's 28px inset exactly. */
    margin-right: 14px;
  }
  .topbar-brand__image {
    height: 38px;
    /* Desktop's brand column is a fixed 248px (var(--sidebar-w)) with no
       neighboring controls competing for the row, so it can afford far more
       than the mobile 56px cap — comfortably inside the column even after
       its 22px left padding + 14px margin-right. */
    max-width: 180px;
  }
}
.topbar-controls {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 28px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
/* [#19] Context navigation takes the same leading topbar slot the workspace
   tabs use on a workspace root — one location signal per page, never two. */
.topbar-context {
  display: flex;
  min-width: 0;
  flex: 0 1 auto;
  align-items: center;
  /* Pull the back control's own padding back to the topbar's left edge so it
     starts on the line the workspace tabs and the page content start on. */
  margin-left: -9px;
}
.topbar-workspace {
  position: relative;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  /* Full-height tabs: stretch to the topbar's own top/bottom edges by
     cancelling out the topbar's vertical padding, so the active tab's
     underline lands on the topbar's own bottom border. */
  align-self: stretch;
  margin: -13px 0;
}
.topbar-workspace .workspace-tabs {
  height: 100%;
  margin: 0;
  border-bottom: 0;
  scrollbar-width: none;
}
.topbar-workspace .workspace-tabs::-webkit-scrollbar {
  display: none;
}
.topbar-workspace .workspace-tab {
  height: 100%;
  min-height: 0;
  padding: 0 10px;
  font-size: 13.5px;
}
.topbar-workspace::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 28px;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), var(--surface));
  pointer-events: none;
  opacity: 0;
}

/* [#1842] Keep the desktop form mounted for the shared server-rendered
   narrowing contract, but the magnifying-glass overlay is the one visible
   search UI at every width. */
.search-wrap {
  display: none;
  flex: 0 1 360px;
  max-width: 360px;
  min-width: 190px;
  margin-left: auto;
  position: relative;
}
.search-wrap svg,
.search-wrap > i {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 14px;
  color: var(--text-3);
  pointer-events: none;
}
.search-input {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 8px 12px 8px 34px;
  color: var(--text-1);
  font-size: 13px;
  transition: border-color 0.15s;
}
.search-input::placeholder {
  color: var(--text-3);
}
.search-input:focus {
  border-color: var(--brass);
  background: var(--surface);
}
.search-input:focus:not(:focus-visible) {
  outline: none;
}

.gsearch-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  /* Right-anchored, so the panel grows leftwards from the docked input and
     never runs off the viewport when the input has shrunk. */
  left: auto;
  right: 0;
  min-width: 320px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
  max-height: 420px;
  overflow-y: auto;
  z-index: 120;
  padding: 4px 0;
}
.gsearch-group {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-3);
  padding: 10px 14px 4px;
}
.gsearch-result {
  display: block;
  padding: 8px 14px;
  color: inherit;
  text-decoration: none;
  border-left: 2px solid transparent;
  cursor: pointer;
}
.gsearch-result.is-highlighted,
.gsearch-result:hover {
  background: var(--surface-hi);
  border-left-color: var(--brass);
}
.gsearch-result-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-1);
  line-height: 1.2;
}
.gsearch-result-subtitle {
  font-size: 11px;
  color: var(--text-3);
  margin-top: 2px;
}
/* #860 — inline stage pill on a closed search result sits smaller than the
   list-view pill so it reads as a tag on the name line. */
.gsearch-result-name .stage-pill {
  font-size: 9px;
  padding: 1px 6px;
  vertical-align: middle;
}
/* Close-reason trail ("Lost 7/19 — Price too high") under a closed result. */
.gsearch-result-meta {
  font-size: 11px;
  color: var(--text-3);
  margin-top: 3px;
  font-style: italic;
}
.gsearch-loading,
.gsearch-empty {
  padding: 14px;
  font-size: 12px;
  color: var(--text-3);
  text-align: center;
}

/* [#3] The narrow action closes the dropdown, behind a rule, carrying the ↵
   glyph because Enter is its real keyboard path. Last position is deliberate:
   it must never steal the first ArrowDown from jump-to-record. */
.gsearch-narrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  margin-top: 4px;
  padding: 9px 14px;
  background: none;
  border: none;
  border-top: 1px solid var(--border);
  border-left: 2px solid transparent;
  font: inherit;
  font-size: 12px;
  color: var(--text-2);
  text-align: left;
  cursor: pointer;
}
.gsearch-narrow.is-highlighted,
.gsearch-narrow:hover {
  background: var(--surface-hi);
  border-left-color: var(--brass);
  color: var(--text-1);
}
.gsearch-narrow__label i {
  margin-right: 6px;
  color: var(--text-3);
}
.gsearch-narrow__hint {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-3);
  flex-shrink: 0;
}

.topbar-btns {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
  margin-left: auto;
}

.view-scroll {
  flex: 1;
  min-width: 0;
  overflow: auto;
  padding: 26px 28px;
  /* [#14] Published so a sticky page header can dock flush with the scrollport
     instead of leaving this padding band for content to show through. */
  --view-pad-top: 26px;
  container-name: app-view;
  container-type: inline-size;
}

/* ═══════════════════════════════════════════
   BUTTONS
═══════════════════════════════════════════ */
.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 18px;
  background: var(--text-1);
  color: #fff;
  border: none;
  border-radius: var(--r-sm);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s;
  white-space: nowrap;
  text-decoration: none;
}
.btn-primary:hover {
  background: #2a4060;
  color: #fff;
}
.btn-primary svg {
  width: 13px;
  height: 13px;
}

.btn-ghost-sm {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 7px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  font-size: 12.5px;
  cursor: pointer;
  transition: all 0.12s;
  text-decoration: none;
  white-space: nowrap;
}
.btn-ghost-sm:hover {
  background: var(--surface-hi);
  color: var(--text-1);
}
.btn-ghost-sm svg {
  width: 13px;
  height: 13px;
}

.btn-danger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: var(--r-sm);
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fca5a5;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.12s;
}
.btn-danger:hover {
  background: #fee2e2;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: var(--r-sm);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border: none;
  transition: all 0.12s;
  text-decoration: none;
}
.btn-secondary {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-2);
}
.btn-secondary:hover {
  background: var(--surface-hi);
  color: var(--text-1);
}
.btn-sm {
  padding: 5px 10px;
  font-size: 12px;
}
.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-2);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.12s;
}

/* ═══════════════════════════════════════════
   FLASH MESSAGES
═══════════════════════════════════════════ */
.flash {
  padding: 10px 16px;
  border-radius: var(--r-sm);
  margin-bottom: 18px;
  font-size: 13px;
}
.flash-notice {
  background: #f0fdf4;
  color: #15803d;
  border: 1px solid #bbf7d0;
}
.flash-alert {
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fca5a5;
}

/* ═══════════════════════════════════════════
   BACK LINK
   [#19] The back-only instance of `.context-nav`. Page-level navigation lives
   in the topbar slot; this stays for back controls that sit inside content
   (a pane, a card) where the topbar slot already belongs to the host page.
═══════════════════════════════════════════ */
.back-link {
  font-size: 12px;
  color: var(--brass-lo);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 14px;
}
.back-link:hover {
  color: var(--brass-lo);
}
/* Sits in a row of controls rather than above a page. */
.back-link--inline {
  margin-bottom: 0;
}

/* ═══════════════════════════════════════════
   TOPBAR + BUTTONS — MOBILE
═══════════════════════════════════════════ */
.mobile-hamburger {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-2);
  font-size: 18px;
  padding: 6px 8px;
  border-radius: var(--r-sm);
  transition: background 0.12s;
  flex-shrink: 0;
}
.mobile-hamburger:hover {
  background: var(--surface-hi);
}

.mobile-search-toggle {
  display: flex;
  align-items: center;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-2);
  font-size: 15px;
  padding: 6px 8px;
  border-radius: var(--r-sm);
  transition: background 0.12s;
}
.mobile-search-toggle:hover {
  background: var(--surface-hi);
}
.mobile-search-toggle[aria-expanded="true"] {
  background: var(--surface-hi);
  color: var(--text-1);
}

.mobile-search-bar {
  display: none;
}
.mobile-search-bar.mobile-search-open {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 1100;
  margin: 0;
  padding: 16px;
  background: rgba(18, 34, 58, 0.45);
  align-items: flex-start;
  justify-content: center;
}
.mobile-search-bar.mobile-search-open .mobile-search-form {
  width: min(100%, 560px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 10px 12px;
  box-shadow: 0 12px 40px rgba(18, 34, 58, 0.18);
}

/* [#3] The mobile bar mounts the same global-search controller as the topbar,
   so it needs the same positioning context for its dropdown. */
.mobile-search-form {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  position: relative;
}
.mobile-search-form > i {
  font-size: 13px;
  flex-shrink: 0;
  color: var(--text-3);
}
.mobile-search-form .search-input {
  flex: 1;
  padding-left: 12px;
}
/* The bar already runs the width of the phone, so the dropdown hangs off it
   rather than off the viewport — `position: fixed` with `top: auto` resolves
   against the viewport in Chrome and lands the panel over the bar it belongs
   to. It scrolls, and its rows clear a 44px touch target. */
/* The mobile bar is full-width, so its panel spans the bar rather than
   right-anchoring off it. */
.gsearch-dropdown--mobile {
  left: 0;
  min-width: 0;
  top: calc(100% + 6px);
  max-height: 60vh;
}
.gsearch-dropdown--mobile .gsearch-result,
.gsearch-dropdown--mobile .gsearch-narrow {
  min-height: 44px;
  padding-top: 10px;
  padding-bottom: 10px;
}

.mobile-search-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-3);
  font-size: 15px;
  padding: 4px 6px;
  flex-shrink: 0;
}

/* Compact shell: navigation becomes a drawer while the full search and page
   controls still fit. */
@media (max-width: 1365px) {
  /* Same breakpoint as the hamburger: logo and the full search field
     leave the topbar so workspace tab labels keep the row. */
  .topbar-brand {
    display: none;
  }
  .mobile-hamburger {
    display: flex;
    align-items: center;
  }
  .topbar,
  .topbar-controls {
    padding-left: 20px;
    padding-right: 20px;
  }
  .view-scroll {
    padding: 20px;
    --view-pad-top: 20px;
  }
  .topbar-workspace {
    flex: 1 1 auto;
    min-width: 0;
  }
  .topbar-workspace .workspace-tabs {
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scroll-padding-inline: 2px;
  }
}

/* Tablet shell: search already collapsed at 1365px; this width only
   tightens page-control wrapping. */
@media (max-width: 1024px) {
  .mobile-hamburger {
    display: flex;
    align-items: center;
  }
  .topbar-controls {
    gap: 8px;
    flex-wrap: wrap;
  }
}

@media (max-width: 768px) {
  .topbar-controls {
    padding: 8px 16px;
  }
  .topbar {
    padding: 10px 16px;
    gap: 8px;
    flex-wrap: wrap;
  }
  .topbar-workspace {
    order: 2;
    flex: 1 1 100%;
    /* Wraps to its own full-width row here, so the desktop stretch trick
       (cancel ALL of .topbar's padding) doesn't apply — instead this row
       breaks out horizontally and pulls flush against .topbar's own bottom
       edge (cancelling its 16px sides / 10px bottom padding only), so the
       active tab's underline lands ON that shared hairline, connected to
       the page below, the same as desktop. The 8px top gap from row 1
       stays untouched. */
    align-self: auto;
    margin: 0 -16px -10px;
  }
  .topbar-workspace .workspace-tabs {
    height: 44px;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scroll-padding-inline: 2px;
  }
  .topbar-workspace .workspace-tab {
    height: 100%;
    min-height: 0;
    flex: 0 0 auto;
    padding: 0 11px;
    font-size: 13px;
  }
  .topbar-workspace .workspace-tab:not(.is-active) {
    justify-content: flex-start;
    width: auto;
  }
  .topbar-workspace .workspace-tab:not(.is-active) .workspace-tab__label,
  .topbar-workspace .workspace-tab.is-active .workspace-tab__label {
    display: inline;
  }
  .topbar-workspace .workspace-tab:not(.is-active) .workspace-tab__count,
  .topbar-workspace .workspace-tab.is-active .workspace-tab__count {
    display: inline;
  }
  .topbar-workspace::after {
    opacity: 1;
  }
  .view-scroll {
    padding: 14px 16px;
    --view-pad-top: 14px;
  }
  .btn-ghost-sm {
    padding: 8px 12px;
    font-size: 12px;
  }
  #flash-messages {
    margin: 0 16px !important;
  }
  .topbar-btns .topbar-new-job {
    padding: 7px 14px;
    font-size: 12px;
  }
}

@media (max-width: 520px) {
  .topbar-btns .topbar-new-job {
    min-width: 64px;
    padding-left: 10px;
    padding-right: 10px;
    justify-content: center;
  }
  .topbar-new-job__label-suffix {
    display: none;
  }
}

/* Masquerade banner — floating pill */
.masquerade-banner {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 9999;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  background: #1c2e42;
  color: #fde68a;
  border-radius: 50px;
  font-size: 13px;
  font-weight: 500;
  box-shadow:
    0 4px 24px rgba(0, 0, 0, 0.25),
    0 0 0 2px #f59e0b;
  white-space: nowrap;
}
.masquerade-banner strong {
  color: #fff;
  font-weight: 700;
}
.masquerade-exit {
  background: rgba(255, 255, 255, 0.15);
  border: none;
  color: #fde68a;
  padding: 5px 12px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  white-space: nowrap;
  transition: background 0.15s;
}
.masquerade-exit:hover {
  background: rgba(255, 255, 255, 0.25);
}
@media (max-width: 768px) {
  .masquerade-banner {
    bottom: 12px;
    padding: 8px 16px;
    font-size: 12px;
    gap: 8px;
  }
}

/* Environment banner — staging indicator */
.env-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 9998;
  text-align: center;
  padding: 3px 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
}
.env-banner-staging {
  background: #f59e0b;
  color: #000;
}
/* Bump masquerade banner up when env banner is present */
body:has(.env-banner) .masquerade-banner {
  bottom: 40px;
}
@media (max-width: 768px) {
  body:has(.env-banner) .masquerade-banner {
    bottom: 32px;
  }
}

/* ═══════════════════════════════════════════
   NOTIFICATION BELL + DROPDOWN
═══════════════════════════════════════════ */
.notif-bell-wrap {
  position: relative;
}
.notif-bell-btn {
  position: relative;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-2);
  font-size: 16px;
  padding: 6px 8px;
  border-radius: var(--r-sm);
  transition:
    background 0.12s,
    color 0.12s;
  display: flex;
  align-items: center;
}
.notif-bell-btn:hover {
  background: var(--surface-hi);
  color: var(--text-1);
}
.notif-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 16px;
  height: 16px;
  line-height: 16px;
  padding: 0 4px;
  background: #ef4444;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  border-radius: 10px;
  text-align: center;
  pointer-events: none;
}

/* Dropdown panel */
.notif-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 360px;
  max-height: 480px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md, 8px);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-8px);
  transition:
    opacity 0.15s,
    transform 0.15s;
}
.notif-dropdown-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.notif-dropdown-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}
.notif-dropdown-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
}
.notif-mark-all {
  font-size: 12px;
  color: var(--brass-lo);
  text-decoration: none;
}
.notif-mark-all:hover {
  text-decoration: underline;
}
.notif-dropdown-list {
  flex: 1;
  overflow-y: auto;
  max-height: 380px;
}
.notif-empty,
.notif-dropdown-loading {
  padding: 32px 16px;
  text-align: center;
  color: var(--text-3);
  font-size: 13px;
}
.notif-item,
.notif-page-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 16px;
  text-decoration: none;
  color: var(--text-2);
  border-bottom: 1px solid var(--border);
  transition: background 0.1s;
  cursor: pointer;
}
.notif-item:hover,
.notif-page-item:hover {
  background: var(--surface-hi);
}
.notif-item:last-child,
.notif-page-item:last-child {
  border-bottom: none;
}
.notif-unread {
  background: rgba(184, 146, 74, 0.06);
}
.notif-unread .notif-message {
  font-weight: 600;
  color: var(--text-1);
}
.notif-icon {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--surface-hi);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: var(--text-3);
  flex-shrink: 0;
  margin-top: 2px;
}
.notif-unread .notif-icon {
  background: rgba(184, 146, 74, 0.15);
  color: var(--brass-lo);
}
.notif-content {
  flex: 1;
  min-width: 0;
}
.notif-message {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-2);
}
.notif-time {
  font-size: 11px;
  color: var(--text-3);
  margin-top: 2px;
}
.notif-source {
  font-size: 11px;
  color: var(--text-3);
  margin-top: 2px;
}
.notif-source-link {
  color: var(--brass-lo);
  text-decoration: none;
}
.notif-source-link:hover {
  text-decoration: underline;
}
.notif-page-item {
  cursor: pointer;
}
.notif-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--brass);
  flex-shrink: 0;
  margin-top: 8px;
}
.notif-dropdown-footer {
  padding: 10px 16px;
  border-top: 1px solid var(--border);
  text-align: center;
}
.notif-view-all {
  font-size: 12px;
  color: var(--brass-lo);
  text-decoration: none;
  font-weight: 500;
}
.notif-view-all:hover {
  text-decoration: underline;
}

.notif-push-btn {
  font-size: 11px;
  padding: 3px 10px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  transition: 0.15s;
}
.notif-push-btn:hover:not(:disabled) {
  border-color: var(--brass);
  color: var(--brass-lo);
}
.notif-push-btn:disabled {
  cursor: default;
}

/* Full page notification list */
.notif-page-list {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md, 8px);
  overflow: hidden;
}
.notif-page-item {
  padding: 14px 20px;
}

@media (max-width: 768px) {
  .notif-dropdown {
    width: 300px;
    right: -40px;
  }
  .notif-page-item {
    padding: 12px 14px;
  }
}

/* ═══════════════════════════════════════════
   TOUCH TARGET FLOOR — coarse pointers only
═══════════════════════════════════════════ */
@media (pointer: coarse) {
  .btn,
  .btn-primary,
  .btn-ghost,
  .btn-sm,
  .btn-ghost-sm,
  .btn-danger {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .mobile-hamburger,
  .mobile-search-toggle,
  .mobile-search-close {
    min-width: 44px;
    min-height: 44px;
  }
  .notif-bell-btn {
    min-width: 44px;
    min-height: 44px;
  }
  .back-link {
    min-height: 44px;
    align-items: center;
  }
  .topbar-workspace .workspace-tab {
    min-height: 44px;
  }
}
