@layer components {
  /* Width of the categories sidebar when it is visible. */
  :root {
    --app-sidebar-width: 19rem;
    /* Minimum viewport width at which the sidebar is allowed to render.
       Below this, we fall back to the original header dropdown layout
       even when the user has enabled the sidebar. */
    --app-sidebar-breakpoint: 900px;
  }

  .app-sidebar {
    display: none;
    position: fixed;
    top: calc(var(--app-header-height, 2.75rem) + var(--blitz-staging-banner-height, 0rem));
    /* Sits at the app column's left edge — flush left on normal screens, offset
       inward when the column is centred on very wide screens. */
    left: var(--app-gutter);
    bottom: 0;
    width: var(--app-sidebar-width);
    background-color: var(--surface);
    border-right: 1px solid var(--sidebar-border);
    flex-direction: column;
    min-height: 0;
    z-index: 50;
    /* Mirror .app-main's padding-top so the sidebar's header row starts at
       the same y as the resource-header row. */
    padding-top: 1rem;
  }

  .app-sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0 1rem;
    /* Matches the .view-toggle-btn height in the resource-header so the
       "Kategorien" row aligns with the "Alle Notizen" row. */
    min-height: 2.5rem;
    border-bottom: 1px solid var(--hairline);
  }

  .app-sidebar-title {
    font-weight: 700;
    font-size: 1.15rem;
    line-height: 1.2;
    letter-spacing: 0.01em;
    color: var(--wine-deep);
    overflow: hidden;
    /* Wrap long category names onto a second line instead of truncating with
       an ellipsis on the first; only clamp once we exceed two lines. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
  }

  .app-sidebar-header-actions {
    display: flex;
    align-items: center;
    gap: 0.1rem;
  }

  /* Header on the note detail page doubles as a "back to the list" link. */
  .app-sidebar-back {
    display: flex;
    align-items: center;
    gap: 0.2rem;
    min-width: 0;
    margin-left: -0.25rem;
    padding: 0.15rem 0.35rem;
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
  }

  .app-sidebar-back:hover {
    background-color: #faf3f1;
    color: var(--wine);
    text-decoration: none;
  }

  .app-sidebar-back-icon {
    --icon-size: 1.1rem;
    color: var(--muted-2);
    flex-shrink: 0;
  }

  .app-sidebar-header-main {
    flex: 1;
    min-width: 0;
  }

  .app-sidebar-icon-btn,
  .sidebar-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border-radius: 8px;
    background: transparent;
    border: none;
    color: var(--muted);
    cursor: pointer;
    --icon-size: 1.4rem;
    transition: background-color 0.15s ease, color 0.15s ease;
  }

  .app-sidebar-icon-btn:hover,
  .sidebar-toggle-btn:hover {
    background-color: #faf3f1;
    color: var(--wine);
    text-decoration: none;
  }

  .app-sidebar-filter {
    position: relative;
    /* margin-top matches .resource-header's margin-bottom so the filter's
       top edge lines up with the first row of cards in the main content. */
    margin: 1rem 0.75rem 0.25rem;
  }

  .app-sidebar-filter-icon {
    --icon-size: 1rem;
    position: absolute;
    left: 0.55rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--muted-2);
    pointer-events: none;
  }

  .app-sidebar-filter-input {
    width: 100%;
    height: 2rem;
    padding: 0 0.6rem 0 1.8rem;
    border: 1px solid transparent;
    border-radius: 10px;
    background-color: #f5e9e3;
    font: inherit;
    font-size: 0.85rem;
    color: var(--ink);
    outline: none;
  }

  .app-sidebar-filter-input::placeholder {
    color: var(--muted-2);
  }

  .app-sidebar-filter-input:focus {
    border-color: var(--wine);
    background-color: white;
  }

  .app-sidebar-item.is-filtered-out {
    display: none;
  }

  .app-sidebar-nav {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0.5rem 0.4rem 0.5rem 0.6rem;
    display: flex;
    flex-direction: column;
    gap: 3px;
  }

  .app-sidebar-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.25rem;
    border-radius: 10px;
    color: var(--wine);
    text-decoration: none;
    font-size: 0.98rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    min-height: 2.4rem;
  }

  .app-sidebar-item:hover {
    background-color: #faf3f1;
    color: var(--wine);
    text-decoration: none;
  }

  /* Keyboard focus ring for ↑/↓ navigation — distinct from the amber
     "selected" (currently open) note. */
  .app-sidebar-item:focus-visible {
    outline: 2px solid #93c5fd;
    outline-offset: -2px;
  }

  .app-sidebar-item.selected {
    background-color: var(--gold);
    color: var(--wine-deep);
    font-weight: 600;
  }

  .app-sidebar-item.selected:hover {
    background-color: var(--gold-hover);
    color: var(--wine-deep);
  }

  /* Category row currently hovered while dragging an item from the list
     (move_to_category_controller). */
  .app-sidebar-item.is-drop-target {
    background-color: #dbeafe;
    box-shadow: inset 0 0 0 2px #60a5fa;
  }

  /* The card/row being dragged onto a sidebar category. */
  .is-dragged {
    opacity: 0.4;
  }

  a.app-sidebar-item,
  .app-sidebar-item-link {
    display: flex;
    align-items: center;
    min-width: 0;
    padding: 0.5rem 0.7rem;
    color: inherit;
    text-decoration: none;
  }

  /* Only the inner link (inside a wrapping .app-sidebar-item <div>) needs to
     grow horizontally to fill the click area next to the action menu. On the
     bare <a class="app-sidebar-item"> ("Alle Notizen"), flex: 1 would make it
     stretch vertically inside the column-flex nav when few categories exist. */
  .app-sidebar-item-link {
    flex: 1;
  }

  .app-sidebar-item-link:hover {
    text-decoration: none;
  }

  /* No extra padding is reserved for the 3-dots menu on hover: the count keeps
     occupying its space while hidden (visibility, not display) and the label's
     fade zone ends before the menu button's footprint (right 0.35rem + 1.75rem
     width), so the visible text never runs under the button. This keeps the
     label showing exactly as much text on hover as at rest. */

  .app-sidebar-item-label {
    overflow: hidden;
    white-space: nowrap;
    min-width: 0;
    /* Fade out overlong names instead of "…" — shows ~2 more characters.
       The fade zone lives in the trailing padding, so names that fit are
       not faded (their glyphs never reach the padding area). */
    padding-right: 1.25rem;
    -webkit-mask-image: linear-gradient(to right, black calc(100% - 1.25rem), transparent);
    mask-image: linear-gradient(to right, black calc(100% - 1.25rem), transparent);
  }

  /* Separator between the pinned "Express-…" bucket and the real categories. */
  .app-sidebar-divider {
    border: none;
    border-top: 1px solid var(--hairline);
    margin: 5px 0.7rem;
  }

  /* Icon sitting right after the "Express-…" label. */
  .app-sidebar-item-icon {
    flex-shrink: 0;
    margin-left: 0.35rem;
    --icon-size: 1rem;
    color: var(--wine);
  }

  /* Category names are shown in upper-case regardless of how they were entered
     (the "Alle Notizen" / uncategorised nav rows use a bare .app-sidebar-item,
     so they are intentionally left as-is). */
  .app-sidebar-item-link .app-sidebar-item-label {
    text-transform: uppercase;
    letter-spacing: 0.02em;
  }

  /* Item count at the row's right edge — quiet, so it informs without
     competing with the wine-coloured names or the gold selection. */
  .app-sidebar-item-count {
    margin-left: auto;
    padding-left: 0.5rem;
    flex-shrink: 0;
    font-size: 0.8rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--muted-2);
  }

  .app-sidebar-item-count.is-zero {
    color: var(--muted-3);
  }

  .app-sidebar-item.selected .app-sidebar-item-count {
    color: var(--gold-ink);
    font-weight: 600;
  }

  /* The 3-dots menu overlays the row's right edge while shown (same states as
     the .app-sidebar-item-link padding rule above), so the count yields to it.
     Guarded on the menu's presence — rows without actions keep their count. */
  .app-sidebar-item:hover:has(.app-sidebar-item-menu) .app-sidebar-item-count,
  .app-sidebar-item:focus-within:has(.app-sidebar-item-menu) .app-sidebar-item-count,
  .app-sidebar-item:has(.dropdown-menu.show) .app-sidebar-item-count {
    visibility: hidden;
  }

  .app-sidebar-item-menu {
    --icon-size: 1.1rem;
    --dropdown-menu-left: auto;
    --dropdown-menu-right: 0;
    /* Absolutely positioned so it overlays the row's right edge instead of
       reserving flow space — that lets the label use the full width at rest. */
    position: absolute;
    right: 0.35rem;
    top: 50%;
    transform: translateY(-50%);
    flex-shrink: 0;
    visibility: hidden;
  }

  .app-sidebar-item:hover .app-sidebar-item-menu,
  .app-sidebar-item-menu:focus-within,
  .app-sidebar-item-menu:has(.dropdown-menu.show) {
    visibility: visible;
  }

  .app-sidebar-item-menu .dropdown-toggle-button {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 4px;
    color: var(--muted-2);
    background: transparent;
    border: none;
    cursor: pointer;
  }

  .app-sidebar-item-menu .dropdown-toggle-button:hover {
    background-color: rgba(138, 39, 64, 0.08);
    color: var(--wine);
  }

  /* The sidebar toggle lives next to the resource title (never inside the
     sidebar) and is a single button that opens or closes the sidebar in either
     state. Hidden below the sidebar breakpoint, where the sidebar is
     force-collapsed and toggling is meaningless; shown on wide screens by the
     media query below. */
  .sidebar-toggle-btn {
    display: none;
  }

  /* Wide viewports: respect the user's saved preference. */
  @media (min-width: 900px) {
    /* On wide screens the sidebar always participates in layout; collapsed vs
       expanded is a slide+fade rather than a display toggle, so it animates
       instead of snapping. Collapsed = translated fully off the left edge and
       faded out; `visibility` flips only after the outro so hidden rows drop
       out of the tab order without cutting the animation short. */
    .app-sidebar {
      display: flex;
      transform: translateX(calc(-100% - var(--app-gutter) - 1px));
      opacity: 0;
      visibility: hidden;
      transition: transform 0.28s ease, opacity 0.28s ease, visibility 0s 0.28s;
    }

    .app-main[data-sidebar="visible"] .app-sidebar {
      transform: translateX(0);
      opacity: 1;
      visibility: visible;
      transition: transform 0.28s ease, opacity 0.28s ease, visibility 0s 0s;
    }

    /* Always visible on wide screens — the same button toggles both ways. */
    .sidebar-toggle-btn {
      display: inline-flex;
    }
  }

  /* Narrow viewports: collapse automatically, no matter what was saved. */
  @media (max-width: 899px) {
    .app-sidebar {
      display: none !important;
    }
  }
}

/* Layout overrides live in the utilities layer so they beat
   .max-width-container's margin-left: auto, which is also in utilities.

   Everything is anchored to the viewport's left edge (never centred) and the
   header is made independent of the sidebar state, so toggling the sidebar
   never shifts the header or the centring of the page — only the main content
   reflows to make room for the sidebar. */
@layer utilities {
  @media (min-width: 900px) {
    /* Content: offset by the gutter (0 — the column is anchored left); only the
       left margin gains the sidebar width when the sidebar is open. The margin
       animates with the same duration/easing as the sidebar's slide (see
       .app-sidebar's `transition: transform 0.28s ease`) so the content's left
       edge and the sidebar's right edge move in lockstep. */
    .app-main {
      transition: margin-left 0.28s ease;
    }

    .app-main[data-sidebar="hidden"] {
      margin-left: var(--app-gutter);
    }

    .app-main[data-sidebar="visible"] {
      margin-left: calc(var(--app-gutter) + var(--app-sidebar-width));
      max-width: calc(var(--content-max-width, 100%) - var(--app-sidebar-width));
    }

    /* Header content: same gutter offset, right edge capped at
       --content-max-width. Independent of sidebar state, so it never moves on
       toggle; centres together with the sidebar and content on wide screens. */
    .app-header > .max-width-container {
      max-width: var(--content-max-width);
      margin-left: var(--app-gutter);
      margin-right: auto;
    }

    /* Width-lock the brand group (TROVARO) so the archive card that follows
       always STARTS on the content column's left edge — aligned with the cards
       and title below (sidebar-width + .app-main's 1rem padding), not on the
       bare sidebar border. Applied in both sidebar states so the card never
       shifts on toggle. Geometry: the archive card's left edge = brand-group
       left (1.25rem header padding) + this width + the 1rem header flex-gap, set
       equal to the content column left (sidebar-width + 1rem), so:
         width = (sidebar-width + 1rem) − 1.25rem − 1rem = sidebar-width − 1.25rem. */
    .header-brand-group {
      width: calc(var(--app-sidebar-width) - 1.25rem);
      flex: 0 0 auto;
    }
  }
}

/* Users who prefer reduced motion get the instant toggle back. */
@media (prefers-reduced-motion: reduce) {
  .app-sidebar,
  .app-main {
    transition: none;
  }
}
