{"version":3,"file":"sidebar.cjs","names":[],"sources":["../src/layout/sidebar/sidebar.ts"],"sourcesContent":["import {\n  bind,\n  createContext,\n  define,\n  getHost,\n  html,\n  inject,\n  onCleanup,\n  onMounted,\n  prop,\n  provide,\n  useEmit,\n  useSlots,\n} from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { createElementSize, createMediaQuery, SentinelUnavailableError } from '@vielzeug/sentinel';\n\nimport '../../content/icon/icon';\nimport { coarsePointerMixin, reducedMotionMixin } from '../../styles';\nimport { computeSafeRel } from '../../utils';\nimport sidebarStyles from './sidebar.css?inline';\nimport groupStyles from './sidebar-group.css?inline';\nimport itemStyles from './sidebar-item.css?inline';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\ntype SidebarVariant = 'floating' | 'inset';\ntype SidebarCollapseSource = 'api' | 'responsive' | 'toggle';\ntype SidebarMobileSource = 'api' | 'responsive' | 'toggle';\ntype SidebarMode = 'bottom-nav' | 'collapsed' | 'default';\n\ntype BottomNavItem = {\n  active: boolean;\n  disabled: boolean;\n  href?: string;\n  iconName?: string;\n  label: string;\n  source: HTMLElement;\n};\n\nconst parseMaxWidthPx = (query: string | undefined): number | undefined => {\n  const value = String(query ?? '').trim();\n\n  if (!value) return undefined;\n\n  const match = /max-width\\s*:\\s*([0-9]+(?:\\.[0-9]+)?)px/i.exec(value);\n\n  if (!match) return undefined;\n\n  const parsed = Number.parseFloat(match[1]);\n\n  return Number.isFinite(parsed) ? parsed : undefined;\n};\n\nconst resolveContainerElement = (el: HTMLElement): HTMLElement | null => {\n  let container = el.parentElement;\n\n  while (container?.tagName.toLowerCase() === 'ore-grid-item') {\n    container = container.parentElement;\n  }\n\n  return container;\n};\n\nconst readContainerWidth = (el: HTMLElement): number => {\n  const parentWidth = resolveContainerElement(el)?.clientWidth ?? 0;\n\n  if (parentWidth > 0) return parentWidth;\n\n  return el.offsetWidth;\n};\n\n/** Context provided by `ore-sidebar` to its `ore-sidebar-group` and `ore-sidebar-item` children. */\nexport type SidebarContext = {\n  collapsed: Readable<boolean>;\n  mobileOpen: Readable<boolean>;\n  mode: Readable<SidebarMode>;\n  variant: Readable<SidebarVariant | undefined>;\n};\n\n/** Injection key for the sidebar context. */\nexport const SIDEBAR_CTX = createContext<SidebarContext>('SidebarContext');\n\n// ─── ore-sidebar styles ──────────────────────────────────────────────────────\n\n/** ore-sidebar element interface */\nexport type SidebarElement = HTMLElement &\n  OreSidebarProps & {\n    /** Close the drawer in bottom-nav mode. */\n    closeMobile(): void;\n    /** Open the drawer in bottom-nav mode. */\n    openMobile(): void;\n    /** Set collapsed state imperatively. */\n    setCollapsed(next: boolean): void;\n    /** Toggle between collapsed and expanded. */\n    toggle(): void;\n    /** Toggle the drawer in bottom-nav mode. */\n    toggleMobile(): void;\n  };\n\n/** Sidebar component properties */\n\nexport type OreSidebarEvents = {\n  'collapsed-change': { collapsed: boolean; source: SidebarCollapseSource };\n  'mobile-open-change': { open: boolean; source: SidebarMobileSource };\n};\n\nexport type OreSidebarGroupEvents = {\n  'open-change': { open: boolean };\n};\n\nexport type OreSidebarProps = {\n  /** CSS media query that switches the sidebar to bottom navigation mode */\n  'bottom-nav-at'?: string;\n  /** Controlled collapsed state */\n  collapsed?: boolean;\n  /** Whether the sidebar supports collapsing */\n  collapsible?: boolean;\n  /** Evaluate responsive and bottom-nav breakpoints against container width only. */\n  'container-breakpoints'?: boolean;\n  /** Initial collapsed state in uncontrolled mode */\n  'default-collapsed'?: boolean;\n  /**\n   * Accessible label for the navigation landmark.\n   * Use to distinguish multiple navigation regions on a page.\n   * @default 'Sidebar navigation'\n   */\n  label?: string;\n  /**\n   * CSS media query that, when it matches, automatically collapses the sidebar.\n   * Unset by default — no automatic collapse.\n   * @example 'responsive=\"(max-width: 768px)\"'\n   */\n  responsive?: string;\n  /** Visual style variant */\n  variant?: SidebarVariant;\n};\n\n/**\n * `ore-sidebar` — A collapsible navigation sidebar with group and item support.\n *\n * @element ore-sidebar\n * @element ore-sidebar-group - Labelled group of navigation items\n * @element ore-sidebar-item - Individual navigation link or button\n *\n * @attr {boolean} collapsed - Controlled collapsed state\n * @attr {boolean} default-collapsed - Initial collapsed state for uncontrolled sidebars\n * @attr {boolean} collapsible - Show the collapse toggle button\n * @attr {string} variant - Visual variant: 'floating' | 'inset'\n * @attr {string} label - Accessible aria-label for the nav landmark\n *\n * @fires collapsed-change - Fired when collapsed state changes. detail: { collapsed: boolean; source: string }\n * @fires mobile-open-change - Fired when mobile overlay open state changes. detail: { open: boolean; source: string }\n *\n * @slot header - Branding or logo content above the nav\n * @slot - Navigation content (ore-sidebar-group / ore-sidebar-item)\n * @slot footer - Footer content below the nav (user info, settings, etc.)\n *\n * @cssprop --sidebar-width - Expanded sidebar width (default: 16rem)\n * @cssprop --sidebar-collapsed-width - Collapsed sidebar width (default: 3.5rem)\n * @cssprop --sidebar-bg - Sidebar background color\n * @cssprop --sidebar-border-color - Border color\n *\n * @part mobile-backdrop - Backdrop shown for mobile overlays.\n * @part nav - Navigation container.\n * @part header - Header container.\n * @part toggle-btn - Shadow part for the `toggle-btn` element.\n * @part content - Content container.\n * @part footer - Footer container.\n * @part bottom-bar - Bottom bar container.\n * @part group - Group container.\n * @part group-header - Group header container.\n * @part group-icon - Group icon container.\n * @part group-label - Group label container.\n * @part group-items - Group items container.\n * @part item-icon - Leading item icon container.\n * @part item-label - Item label container.\n * @part item-end - Trailing item content container.\n * @part item - Item root element.\n * @example\n * ```html\n * <ore-sidebar collapsible label=\"App navigation\">\n *   <span slot=\"header\">My App</span>\n *   <ore-sidebar-group label=\"Main\">\n *     <ore-sidebar-item href=\"/dashboard\" active>Dashboard</ore-sidebar-item>\n *     <ore-sidebar-item href=\"/settings\">Settings</ore-sidebar-item>\n *   </ore-sidebar-group>\n * </ore-sidebar>\n *\n * <!-- Auto-collapse on mobile -->\n * <ore-sidebar collapsible responsive=\"(max-width: 768px)\">...</ore-sidebar>\n * ```\n */\nexport const SIDEBAR_TAG = 'ore-sidebar' as const;\ndefine<OreSidebarProps>(SIDEBAR_TAG, {\n  props: {\n    'bottom-nav-at': prop.string(),\n    collapsed: prop.bool(false),\n    collapsible: prop.bool(false),\n    'container-breakpoints': prop.bool(false),\n    'default-collapsed': prop.bool(false),\n    label: prop.string('Sidebar navigation'),\n    responsive: prop.string(),\n    variant: prop.string<SidebarVariant>(),\n  },\n  setup(props) {\n    const el = getHost();\n    const emit = useEmit<OreSidebarEvents>();\n    const slots = useSlots();\n\n    const hasHeader = () => slots.has('header').value;\n    const hasFooter = () => slots.has('footer').value;\n    const hasLogo = () => slots.has('logo').value;\n\n    const isControlled = signal(el.hasAttribute('collapsed'));\n    const collapsedState = signal(isControlled.value ? el.hasAttribute('collapsed') : props['default-collapsed'].value);\n    const isBottomNav = signal(false);\n    const isMobileOpen = signal(false);\n    const bottomNavItems = signal<BottomNavItem[]>([]);\n    const responsiveMediaMatches = signal(false);\n    const responsiveSizeMatches = signal(false);\n    const responsiveMaxWidthPx = signal<number | undefined>(parseMaxWidthPx(props.responsive.value));\n    const hasResponsiveQuery = signal(Boolean(String(props.responsive.value ?? '').trim()));\n    const bottomNavMediaMatches = signal(false);\n    const bottomNavSizeMatches = signal(false);\n    const bottomNavMaxWidthPx = signal<number | undefined>(parseMaxWidthPx(props['bottom-nav-at'].value));\n    const isPreviewMode = signal(false);\n\n    const isCollapsed = () => collapsedState.value;\n    const mode = computed<SidebarMode>(() => {\n      if (isBottomNav.value) return 'bottom-nav';\n\n      return collapsedState.value ? 'collapsed' : 'default';\n    });\n\n    const applyResponsiveState = () => {\n      const useContainerBreakpoints = props['container-breakpoints'].value;\n      const responsiveMatched = useContainerBreakpoints\n        ? responsiveSizeMatches.value\n        : responsiveMediaMatches.value || responsiveSizeMatches.value;\n      const bottomMatched = useContainerBreakpoints\n        ? bottomNavSizeMatches.value\n        : bottomNavMediaMatches.value || bottomNavSizeMatches.value;\n\n      // If the mobile drawer is currently open, stay in bottom-nav mode\n      // regardless of the responsive match. This prevents the drawer from\n      // disappearing mid-animation or if forced open via the API on desktop.\n      if (!isMobileOpen.value) {\n        isBottomNav.value = bottomMatched;\n      }\n\n      if (!bottomMatched && !isMobileOpen.value) {\n        setMobileOpen(false, 'responsive');\n      }\n\n      if (hasResponsiveQuery.value) {\n        setCollapsed(responsiveMatched, 'responsive');\n      }\n    };\n\n    const readBottomNavItems = () => {\n      const next = slots\n        .elements()\n        .value.filter(\n          (el): el is HTMLElement => el instanceof HTMLElement && el.tagName.toLowerCase() === 'ore-sidebar-item',\n        )\n        .map((el, index) => {\n          const iconSlotEl =\n            (el.querySelector(':scope > [slot=\"icon\"]') as HTMLElement | null) ??\n            (el.querySelector('[slot=\"icon\"]') as HTMLElement | null);\n          const directIconName =\n            iconSlotEl?.tagName.toLowerCase() === 'ore-icon' ? iconSlotEl.getAttribute('name') : null;\n          const nestedIconName = iconSlotEl?.querySelector('ore-icon')?.getAttribute('name') ?? null;\n          const rawLabel = (el.textContent ?? '').trim();\n\n          return {\n            active: el.hasAttribute('active'),\n            disabled: el.hasAttribute('disabled'),\n            href: el.getAttribute('href') ?? undefined,\n            iconName: directIconName ?? nestedIconName ?? undefined,\n            label: rawLabel || `Item ${index + 1}`,\n            source: el,\n          } satisfies BottomNavItem;\n        });\n\n      bottomNavItems.value = next;\n    };\n\n    provide(SIDEBAR_CTX, {\n      collapsed: computed(() => !isBottomNav.value && collapsedState.value) as Readable<boolean>,\n      mobileOpen: computed(() => isBottomNav.value && isMobileOpen.value) as Readable<boolean>,\n      mode: mode as Readable<SidebarMode>,\n      variant: props.variant,\n    });\n\n    const setCollapsed = (next: boolean, source: SidebarCollapseSource) => {\n      if (isCollapsed() === next) return;\n\n      if (!isControlled.value) {\n        collapsedState.value = next;\n      }\n\n      emit('collapsed-change', { collapsed: next, source });\n    };\n\n    const setMobileOpen = (next: boolean, source: SidebarMobileSource) => {\n      const open = Boolean(next);\n\n      if (open && !isBottomNav.value) {\n        isBottomNav.value = true;\n      }\n\n      if (!isBottomNav.value && !open) {\n        if (isMobileOpen.value) {\n          isMobileOpen.value = false;\n        }\n\n        return;\n      }\n\n      if (isMobileOpen.value === open) return;\n\n      isMobileOpen.value = open;\n\n      // If closing, re-evaluate responsive state to potentially exit forced bottom-nav mode\n      if (!open) {\n        applyResponsiveState();\n      }\n\n      emit('mobile-open-change', { open, source });\n    };\n\n    const doToggle = () => {\n      setCollapsed(!isCollapsed(), 'toggle');\n    };\n\n    const sidebarEl = el as SidebarElement;\n\n    sidebarEl.setCollapsed = (next) => setCollapsed(Boolean(next), 'api');\n    sidebarEl.toggle = doToggle;\n    sidebarEl.openMobile = () => setMobileOpen(true, 'api');\n    sidebarEl.closeMobile = () => setMobileOpen(false, 'api');\n    sidebarEl.toggleMobile = () => setMobileOpen(!isMobileOpen.value, 'toggle');\n\n    bind({\n      attr: {\n        'data-bottom-nav': () => (isBottomNav.value ? true : undefined),\n        'data-collapsed': () => (isCollapsed() && !isBottomNav.value ? true : undefined),\n        'data-mobile-open': () => (isBottomNav.value && isMobileOpen.value ? true : undefined),\n        'data-preview-mode': () => (isPreviewMode.value ? true : undefined),\n      },\n    });\n\n    onMounted(() => {\n      // Suppress transitions during initial layout so the sidebar doesn't\n      // animate from a collapsed/0 state before the first ResizeObserver fires.\n      el.setAttribute('data-no-transition', '');\n\n      let transitionUnlocked = false;\n      const unlockTransition = () => {\n        if (transitionUnlocked) return;\n\n        transitionUnlocked = true;\n        el.removeAttribute('data-no-transition');\n      };\n\n      // Fallback: unlock after two frames in case ResizeObserver doesn't fire.\n      requestAnimationFrame(() => requestAnimationFrame(unlockTransition));\n\n      let mediaCleanup: (() => void) | undefined;\n      let bottomNavCleanup: (() => void) | undefined;\n      const itemObservers = new Map<HTMLElement, MutationObserver>();\n      const observer = new MutationObserver(() => {\n        if (!el.hasAttribute('collapsed') && !isControlled.value) return;\n\n        isControlled.value = true;\n        collapsedState.value = el.hasAttribute('collapsed');\n      });\n\n      observer.observe(el, {\n        attributeFilter: ['collapsed'],\n        attributes: true,\n      });\n\n      watch(\n        props.responsive,\n        (query) => {\n          mediaCleanup?.();\n          mediaCleanup = undefined;\n\n          const mediaQuery = String(query ?? '').trim();\n\n          hasResponsiveQuery.value = Boolean(mediaQuery);\n          responsiveMaxWidthPx.value = parseMaxWidthPx(mediaQuery);\n          responsiveMediaMatches.value = false;\n\n          const width = readContainerWidth(el);\n\n          responsiveSizeMatches.value =\n            width > 0 && responsiveMaxWidthPx.value != null ? width <= responsiveMaxWidthPx.value : false;\n          applyResponsiveState();\n\n          // For parseable max-width queries, keep behavior container-driven.\n          // This avoids preview viewport controls being overridden by window width.\n          if (props['container-breakpoints'].value && responsiveMaxWidthPx.value != null) {\n            return;\n          }\n\n          if (!mediaQuery) {\n            return;\n          }\n\n          try {\n            const mediaHandle = createMediaQuery(mediaQuery);\n            const syncMedia = (state: typeof mediaHandle.value) => {\n              if (state) {\n                responsiveMediaMatches.value = state.matches;\n                applyResponsiveState();\n              }\n            };\n\n            syncMedia(mediaHandle.value);\n\n            const mediaCleanupFn = watch(mediaHandle, syncMedia);\n            mediaCleanup = () => {\n              mediaCleanupFn.dispose();\n              mediaHandle.dispose();\n            };\n          } catch (error) {\n            if (!(error instanceof SentinelUnavailableError)) throw error;\n          }\n        },\n        { immediate: true },\n      );\n\n      watch(\n        props['bottom-nav-at'],\n        (query) => {\n          bottomNavCleanup?.();\n          bottomNavCleanup = undefined;\n\n          const mediaQuery = String(query ?? '').trim();\n\n          bottomNavMaxWidthPx.value = parseMaxWidthPx(mediaQuery);\n          bottomNavMediaMatches.value = false;\n\n          const width = readContainerWidth(el);\n\n          bottomNavSizeMatches.value =\n            width > 0 && bottomNavMaxWidthPx.value != null ? width <= bottomNavMaxWidthPx.value : false;\n          applyResponsiveState();\n\n          // For parseable max-width queries, keep behavior container-driven.\n          // This avoids preview viewport controls being overridden by window width.\n          if (props['container-breakpoints'].value && bottomNavMaxWidthPx.value != null) {\n            return;\n          }\n\n          if (!mediaQuery) {\n            return;\n          }\n\n          try {\n            const mediaHandle = createMediaQuery(mediaQuery);\n            const syncMedia = (state: typeof mediaHandle.value) => {\n              if (state) {\n                bottomNavMediaMatches.value = state.matches;\n                applyResponsiveState();\n              }\n            };\n\n            syncMedia(mediaHandle.value);\n\n            const mediaCleanupFn = watch(mediaHandle, syncMedia);\n            bottomNavCleanup = () => {\n              mediaCleanupFn.dispose();\n              mediaHandle.dispose();\n            };\n          } catch (error) {\n            if (!(error instanceof SentinelUnavailableError)) throw error;\n          }\n        },\n        { immediate: true },\n      );\n\n      const stopResizeEffect =\n        typeof ResizeObserver === 'function'\n          ? (() => {\n              const hostSize = createElementSize(el);\n              onCleanup(() => hostSize.dispose());\n\n              const wrapperEl = el.parentElement;\n              const containerEl = resolveContainerElement(el);\n              const wrapperSize = wrapperEl ? createElementSize(wrapperEl) : undefined;\n              const parentSize = containerEl && containerEl !== wrapperEl ? createElementSize(containerEl) : undefined;\n\n              if (wrapperSize) {\n                onCleanup(() => wrapperSize.dispose());\n              }\n              if (parentSize) {\n                onCleanup(() => parentSize.dispose());\n              }\n\n              let rafId: number | undefined;\n\n              const onResize = () => {\n                if (rafId !== undefined) cancelAnimationFrame(rafId);\n\n                rafId = requestAnimationFrame(() => {\n                  const resolvedContainer = resolveContainerElement(el);\n                  const width = readContainerWidth(el);\n                  const responsiveWasMatched = responsiveSizeMatches.value;\n                  const bottomNavWasMatched = bottomNavSizeMatches.value;\n                  const parentWidth = resolvedContainer?.clientWidth ?? 0;\n\n                  isPreviewMode.value = parentWidth > 0 && parentWidth < window.innerWidth;\n\n                  responsiveSizeMatches.value =\n                    width > 0 && responsiveMaxWidthPx.value != null ? width <= responsiveMaxWidthPx.value : false;\n                  bottomNavSizeMatches.value =\n                    width > 0 && bottomNavMaxWidthPx.value != null ? width <= bottomNavMaxWidthPx.value : false;\n\n                  if (\n                    responsiveWasMatched !== responsiveSizeMatches.value ||\n                    bottomNavWasMatched !== bottomNavSizeMatches.value\n                  ) {\n                    applyResponsiveState();\n                  }\n\n                  unlockTransition();\n                });\n              };\n\n              return watch(\n                computed(() => [\n                  hostSize.value?.width,\n                  hostSize.value?.height,\n                  wrapperSize?.value?.width,\n                  wrapperSize?.value?.height,\n                  parentSize?.value?.width,\n                  parentSize?.value?.height,\n                ]),\n                onResize,\n              );\n            })()\n          : undefined;\n\n      const bindItemObservers = (items: HTMLElement[]) => {\n        const set = new Set(items);\n\n        for (const [item, cleanup] of itemObservers) {\n          if (set.has(item)) continue;\n\n          cleanup.disconnect();\n          itemObservers.delete(item);\n        }\n\n        for (const item of items) {\n          if (itemObservers.has(item)) continue;\n\n          const itemObserver = new MutationObserver(() => {\n            // Only update if in bottom-nav mode to minimize re-renders\n            if (isBottomNav.value) {\n              readBottomNavItems();\n            }\n          });\n\n          // Only watch attributes that affect bottom-nav rendering; skip childList/subtree/characterData\n          itemObserver.observe(item, {\n            attributeFilter: ['active', 'disabled', 'href'],\n            attributes: true,\n          });\n          itemObservers.set(item, itemObserver);\n        }\n      };\n\n      watch(\n        slots.elements(),\n        (elements) => {\n          const directItems = elements.filter(\n            (el): el is HTMLElement => el instanceof HTMLElement && el.tagName.toLowerCase() === 'ore-sidebar-item',\n          );\n\n          bindItemObservers(directItems);\n          readBottomNavItems();\n        },\n        { immediate: true },\n      );\n\n      return () => {\n        observer.disconnect();\n        mediaCleanup?.();\n        bottomNavCleanup?.();\n        stopResizeEffect?.dispose();\n\n        for (const itemObserver of itemObservers.values()) {\n          itemObserver.disconnect();\n        }\n\n        itemObservers.clear();\n      };\n    });\n\n    return html`\n      <button\n        class=\"mobile-backdrop\"\n        part=\"mobile-backdrop\"\n        type=\"button\"\n        aria-label=\"Close sidebar\"\n        ?hidden=${() => !isBottomNav.value || !isMobileOpen.value}\n        @click=${() => setMobileOpen(false, 'toggle')}></button>\n      <nav aria-label=\"${props.label}\" part=\"nav\">\n        <div class=\"sidebar-header\" part=\"header\" ?hidden=${() => !hasHeader() && !props.collapsible.value}>\n          <span class=\"sidebar-logo\" ?hidden=${() => !hasLogo()}>\n            <slot name=\"logo\"></slot>\n          </span>\n          <span class=\"sidebar-header-content\">\n            <slot name=\"header\"></slot>\n          </span>\n          <button\n            class=\"toggle-btn\"\n            part=\"toggle-btn\"\n            type=\"button\"\n            ?hidden=${() => !props.collapsible.value}\n            aria-label=\"${() => (isCollapsed() ? 'Expand sidebar' : 'Collapse sidebar')}\"\n            aria-expanded=\"${() => !isCollapsed()}\"\n            @click=\"${doToggle}\">\n            <span class=\"toggle-icon\" aria-hidden=\"true\">\n              <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n            </span>\n          </button>\n        </div>\n        <div class=\"sidebar-content\" part=\"content\">\n          <slot></slot>\n        </div>\n        <div class=\"sidebar-footer\" part=\"footer\" ?hidden=${() => !hasFooter()}>\n          <slot name=\"footer\"></slot>\n        </div>\n      </nav>\n\n      <div class=\"bottom-bar\" part=\"bottom-bar\" ?hidden=${() => !isBottomNav.value}>\n        ${() =>\n          bottomNavItems.value.map((item) => {\n            const className = `bottom-tab${item.active ? ' bottom-tab-active' : ''}`;\n\n            if (item.href && !item.disabled) {\n              return html`\n                <a\n                  class=\"${className}\"\n                  href=\"${item.href}\"\n                  aria-current=\"${item.active ? 'page' : null}\"\n                  data-active=\"${item.active ? 'true' : null}\">\n                  <span class=\"bottom-tab-icon\" aria-hidden=\"true\" ?hidden=${() => !item.iconName}>\n                    <ore-icon name=\"${item.iconName}\" size=\"18\" stroke-width=\"2\"></ore-icon>\n                  </span>\n                  <span class=\"bottom-tab-label\">${item.label}</span>\n                </a>\n              `;\n            }\n\n            return html`\n              <button\n                class=\"${className}\"\n                type=\"button\"\n                ?disabled=${item.disabled}\n                aria-current=\"${item.active ? 'page' : null}\"\n                data-active=\"${item.active ? 'true' : null}\"\n                @click=${() => item.source.click()}>\n                <span class=\"bottom-tab-icon\" aria-hidden=\"true\" ?hidden=${() => !item.iconName}>\n                  <ore-icon name=\"${item.iconName}\" size=\"18\" stroke-width=\"2\"></ore-icon>\n                </span>\n                <span class=\"bottom-tab-label\">${item.label}</span>\n              </button>\n            `;\n          })}\n      </div>\n    `;\n  },\n  styles: [coarsePointerMixin, reducedMotionMixin, sidebarStyles],\n});\n\n// ─── ore-sidebar-group styles ────────────────────────────────────────────────\n\n/** Sidebar group properties */\nexport type OreSidebarGroupProps = {\n  /** Whether this group can be collapsed */\n  collapsible?: boolean;\n  /** Initial open state in uncontrolled mode */\n  'default-open'?: boolean;\n  /** Accessible label for the group */\n  label?: string;\n  /** Controlled open state */\n  open?: boolean;\n};\n\n/**\n * `ore-sidebar-group` — A labelled section within `ore-sidebar`.\n *\n * @element ore-sidebar-group\n *\n * @attr {string} label - Group label text\n * @attr {boolean} collapsible - Whether this group can be toggled open/closed\n * @attr {boolean} open - Controlled expanded state\n * @attr {boolean} default-open - Initial expanded state in uncontrolled mode\n *\n * @fires open-change - Fired when the group open state changes (collapsible groups only). detail: { open: boolean }\n *\n * @slot - Navigation items (`ore-sidebar-item`)\n * @slot icon - Icon displayed before the label\n *\n * @example\n * ```html\n * <ore-sidebar-group label=\"Main\" collapsible open>\n *   <ore-sidebar-item href=\"/home\">Home</ore-sidebar-item>\n * </ore-sidebar-group>\n * ```\n */\nexport const SIDEBAR_GROUP_TAG = 'ore-sidebar-group' as const;\ndefine<OreSidebarGroupProps>(SIDEBAR_GROUP_TAG, {\n  props: {\n    collapsible: prop.bool(false),\n    'default-open': prop.bool(true),\n    label: prop.string(),\n    open: {\n      default: undefined as boolean | undefined,\n      parse: (value: string | null) => (value == null ? undefined : value === '' || value === 'true'),\n      reflect: false,\n    },\n  },\n  setup(props) {\n    const slots = useSlots();\n\n    const hasIcon = () => slots.has('icon').value;\n    const sidebarCtx = inject(SIDEBAR_CTX);\n\n    bind({\n      attr: {\n        'sidebar-bottom-nav': () =>\n          sidebarCtx?.mode.value === 'bottom-nav' && !sidebarCtx?.mobileOpen.value ? true : undefined,\n        'sidebar-collapsed': () => (sidebarCtx?.collapsed.value ? true : undefined),\n      },\n    });\n\n    const isControlled = () => props.open.value !== undefined;\n    const openState = signal(props['default-open'].value);\n    const isOpen = computed(() => {\n      if (!props.collapsible.value) return true;\n\n      if (isControlled()) return props.open.value ?? false;\n\n      return openState.value;\n    });\n\n    watch(props.open, (value) => {\n      if (value === undefined) return;\n\n      openState.value = value;\n    });\n\n    bind({\n      attr: {\n        open: () => (isOpen.value ? true : undefined),\n      },\n    });\n\n    return html`\n      <details class=\"group\" part=\"group\" ?open=${isOpen}>\n        <summary\n          class=\"group-header\"\n          part=\"group-header\"\n          aria-expanded=\"${() => (props.collapsible.value ? String(props.open.value) : null)}\"\n          @click=${(e: MouseEvent) => {\n            if (!props.collapsible.value) {\n              e.preventDefault();\n            }\n          }}>\n          <span class=\"group-icon\" part=\"group-icon\" ?hidden=${() => !hasIcon()} aria-hidden=\"true\">\n            <slot name=\"icon\"></slot>\n          </span>\n          <span class=\"group-label\" part=\"group-label\">${props.label}</span>\n          <span class=\"chevron\" ?hidden=${() => !props.collapsible.value} aria-hidden=\"true\">\n            <ore-icon name=\"chevron-right\" size=\"12\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n          </span>\n        </summary>\n        <div class=\"group-items\" part=\"group-items\" role=\"list\">\n          <slot></slot>\n        </div>\n      </details>\n    `;\n  },\n  styles: [reducedMotionMixin, groupStyles],\n});\n\n// ─── ore-sidebar-item styles ─────────────────────────────────────────────────\n\n/** Sidebar item properties */\nexport type OreSidebarItemProps = {\n  /** Whether this item represents the current page/section */\n  active?: boolean;\n  /** Whether this item is disabled */\n  disabled?: boolean;\n  /** Navigation href — renders an `<a>` when set, otherwise a `<button>` */\n  href?: string;\n  /**\n   * Relationship of the linked URL (`rel` attribute on the inner `<a>`).\n   * Only applies when `href` is set.\n   */\n  rel?: string;\n  /**\n   * Browsing context for the link (`target` attribute on the inner `<a>`).\n   * Only applies when `href` is set.\n   */\n  target?: string;\n};\n\n/**\n * `ore-sidebar-item` — An individual navigation item in a `ore-sidebar`.\n *\n * Renders as an `<a>` when `href` is provided, otherwise as a `<button>`.\n * Marks the active page via `aria-current=\"page\"` when the `active` attribute is set.\n *\n * @element ore-sidebar-item\n *\n * @attr {string} href - Link URL; renders an anchor when set\n * @attr {boolean} active - Marks the item as the current page\n * @attr {boolean} disabled - Disables the item\n * @attr {string} rel - Anchor `rel` attribute (links only)\n * @attr {string} target - Anchor `target` attribute (links only)\n *\n * @slot - Label text\n * @slot icon - Leading icon\n * @slot end - Trailing content (badge, shortcut, arrow, etc.)\n *\n * @cssprop --sidebar-item-color - Default text color\n * @cssprop --sidebar-item-hover-bg - Hover background\n * @cssprop --sidebar-item-hover-color - Hover text color\n * @cssprop --sidebar-item-active-bg - Active background\n * @cssprop --sidebar-item-active-color - Active text color\n * @cssprop --sidebar-item-indicator - Active indicator bar color\n *\n * @part item - The inner anchor or button element\n * @part item-icon - The icon wrapper\n * @part item-label - The label wrapper\n * @part item-end - The trailing content wrapper\n *\n * @example\n * ```html\n * <ore-sidebar-item href=\"/dashboard\" active>\n *   <span slot=\"icon\">🏠</span>\n *   Dashboard\n * </ore-sidebar-item>\n *\n * <ore-sidebar-item href=\"/users\">\n *   <span slot=\"icon\">👤</span>\n *   Users\n *   <ore-badge slot=\"end\" color=\"primary\">3</ore-badge>\n * </ore-sidebar-item>\n * ```\n */\nexport const SIDEBAR_ITEM_TAG = 'ore-sidebar-item' as const;\ndefine<OreSidebarItemProps>(SIDEBAR_ITEM_TAG, {\n  props: {\n    active: prop.bool(false),\n    disabled: prop.bool(false),\n    href: prop.string(),\n    rel: prop.string(),\n    target: prop.string(),\n  },\n  setup(props) {\n    const slots = useSlots();\n\n    const hasIcon = () => slots.has('icon').value;\n    const hasEnd = () => slots.has('end').value;\n    const sidebarCtx = inject(SIDEBAR_CTX);\n\n    bind({\n      attr: {\n        'sidebar-bottom-nav': () =>\n          sidebarCtx?.mode.value === 'bottom-nav' && !sidebarCtx?.mobileOpen.value ? true : undefined,\n        'sidebar-collapsed': () => (sidebarCtx?.collapsed.value ? true : undefined),\n      },\n    });\n\n    const isLink = () => !!props.href.value && !props.disabled.value;\n\n    // Prevent reverse tabnapping: auto-inject noopener + noreferrer for _blank links.\n    const effectiveRel = computed(() => computeSafeRel(props.rel.value, props.target.value));\n\n    const renderItemContent = () => html`\n      <span class=\"item-icon\" part=\"item-icon\" ?hidden=${() => !hasIcon()} aria-hidden=\"true\">\n        <slot name=\"icon\"></slot>\n      </span>\n      <span class=\"item-label\" part=\"item-label\"><slot></slot></span>\n      <span class=\"item-end\" part=\"item-end\" ?hidden=${() => !hasEnd()}>\n        <slot name=\"end\"></slot>\n      </span>\n    `;\n\n    return html`\n      ${() => {\n        if (isLink()) {\n          return html`\n            <a\n              class=\"item\"\n              part=\"item\"\n              href=\"${props.href}\"\n              rel=\"${effectiveRel}\"\n              target=\"${props.target}\"\n              aria-current=\"${() => (props.active.value ? 'page' : null)}\">\n              ${renderItemContent()}\n            </a>\n          `;\n        }\n\n        if (props.disabled.value) {\n          return html`\n            <div\n              class=\"item\"\n              part=\"item\"\n              aria-disabled=\"true\"\n              tabindex=\"-1\"\n              aria-current=\"${() => (props.active.value ? 'page' : null)}\">\n              ${renderItemContent()}\n            </div>\n          `;\n        }\n\n        return html`\n          <button\n            class=\"item\"\n            part=\"item\"\n            type=\"button\"\n            ?disabled=\"${props.disabled}\"\n            aria-current=\"${() => (props.active.value ? 'page' : null)}\">\n            ${renderItemContent()}\n          </button>\n        `;\n      }}\n    `;\n  },\n  styles: [coarsePointerMixin, itemStyles],\n});\n"],"mappings":"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"}