{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sidebar",
  "title": "Sidebar",
  "description": "A column of words beside the work. Folded, it becomes a ruler: a numeral for each group, a tick for each link, and the name comes out into the margin when you point at it.",
  "dependencies": [
    "@radix-ui/react-slot"
  ],
  "registryDependencies": [
    "https://thedirectors.agency/ui/r/0nlytype.json",
    "https://thedirectors.agency/ui/r/button.json",
    "https://thedirectors.agency/ui/r/scrollbar.json",
    "https://thedirectors.agency/ui/r/sheet.json"
  ],
  "files": [
    {
      "path": "registry/0nlytype/ui/sidebar.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { Slot } from \"@radix-ui/react-slot\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport { Scrollbar, type ScrollbarSection } from \"@/components/ui/scrollbar\"\nimport { Sheet, SheetContent, SheetSpine, SheetTitle, SheetTrigger } from \"@/components/ui/sheet\"\n\n/** The width at which the words fit beside the work. It is also in sidebar.css: a media query can't read a variable. */\nconst BREAKPOINT = 860\nconst WIDE = `(min-width: ${BREAKPOINT}px)`\n\n/** true once the window is wide; null until the browser has said (the server and the first paint show both surfaces and let CSS choose). */\nfunction useWide() {\n  return React.useSyncExternalStore<boolean | null>(\n    (notify) => {\n      const query = matchMedia(WIDE)\n      query.addEventListener(\"change\", notify)\n      return () => query.removeEventListener(\"change\", notify)\n    },\n    () => matchMedia(WIDE).matches,\n    () => null,\n  )\n}\n\n/** Splits a group's name into the part that stays when the column is folded and the part that folds away: \"VI Controls\" keeps \"VI\", \"Start\" keeps \"S\". */\nfunction split(label: string): { mark: string; rest: string; numeral: boolean } {\n  const [first, ...more] = label.split(\" \")\n  if (more.length && /^[IVXLCDM]+$/.test(first)) return { mark: first, rest: more.join(\" \"), numeral: true }\n  const [initial, ...rest] = Array.from(label)\n  return { mark: initial ?? \"\", rest: rest.join(\"\"), numeral: false }\n}\n\n/** Keep a word's initial when folded. Anything that isn't plain text is left alone. */\nfunction fold(node: React.ReactNode): React.ReactNode {\n  if (typeof node !== \"string\" || node.length < 2) return node\n  const { mark, rest } = split(node)\n  return (\n    // bdi: the two halves are inline-blocks, which bidi treats as neutral, so in a right-to-left page \"Start\" read\n    // \"tartS\". Isolated, they take their order from the word's own letters.\n    <bdi>\n      <span className=\"ot-sidebar-i\">{mark}</span>\n      <span className=\"ot-sidebar-rest\">{rest}</span>\n    </bdi>\n  )\n}\n\n/** The groups in the list, as marks for the column's rail: a string, so React can tell when it changed. */\nconst readGroups = (list: HTMLElement | null) =>\n  JSON.stringify(\n    [...(list?.querySelectorAll<HTMLElement>(\"[data-slot=sidebar-label]\") ?? [])].map((l) => {\n      const { mark, rest, numeral } = split(l.dataset.name ?? \"\")\n      return { id: l.id, num: numeral ? mark : \"\", name: numeral ? rest : (l.dataset.name ?? \"\") }\n    }),\n  )\nconst never = () => () => {}\n\n/** What is being pointed at while folded: it gets its name in the margin, on a leader line. */\ntype Peek = { key: string; name: string; group: string; y: number; edge: number; rtl: boolean }\ntype Peeking = { peek: Peek | null; slot: HTMLElement | null; folded: boolean }\nconst PeekContext = React.createContext<Peeking>({ peek: null, slot: null, folded: false })\n\ntype SidebarProps = Omit<React.ComponentProps<\"nav\">, \"aria-label\"> & {\n  /** Names the landmark: \"Studio app\", \"Docs\". */\n  label: string\n  /** The trigger's word, and the sheet's name, when the window is too narrow for the column. */\n  sheetLabel?: string\n  /** The column folds to a ruler: each group keeps its numeral or initial, each link a tick, and pointing at or focusing one draws its name (and a link's preview) in the margin. */\n  folded?: boolean\n  /** Smaller words, closer together: for a long index. */\n  compact?: boolean\n  /**\n   * words: every group open. chapter: only the group you are in stands open; the others keep their names, and open\n   * for a still pointer or for focus. numerals: each group's place (01, 02) set large in the\n   * margin, its label and links small beside it. Unfolded only: folded, every variant is the ruler.\n   */\n  variant?: \"words\" | \"chapter\" | \"numerals\"\n}\n\n/**\n * A column of words beside the work. Wide, it stands inline; narrow, only a quiet trigger shows\n * and the same words open in a sheet. Choosing a link in the sheet puts it away.\n */\nfunction Sidebar({ label, sheetLabel = \"Index\", folded, compact, variant = \"words\", className, children, onScroll, ...props }: SidebarProps) {\n  const wide = useWide()\n  const [open, setOpen] = React.useState(false)\n  // Widening puts the sheet away, so it isn't waiting open when the window narrows again.\n  const [was, setWas] = React.useState(wide)\n  if (wide !== was) {\n    setWas(wide)\n    if (wide) setOpen(false)\n  }\n\n  // Pointing at a tick (or focusing it) names it in the margin. One callout is shared, and follows.\n  const [peek, setPeek] = React.useState<Peek | null>(null)\n  const [slot, setSlot] = React.useState<HTMLElement | null>(null)\n  const [hushed, setHushed] = React.useState(false)\n  const target = React.useRef<HTMLElement | null>(null)\n  const callout = React.useRef<HTMLDivElement>(null)\n  const list = React.useRef<HTMLDivElement>(null)\n  const ruler = folded && wide !== false\n  // Unfolding, or the window narrowing: nothing is pointed at any more.\n  const [wasRuler, setWasRuler] = React.useState(ruler)\n  if (ruler !== wasRuler) {\n    setWasRuler(ruler)\n    setPeek(null)\n  }\n\n  // Each group is a mark on the column's rail, as a page's sections are on the page's. Folded, the ruler already numbers them.\n  const groups = React.useSyncExternalStore(never, () => (ruler ? \"[]\" : readGroups(list.current)), () => \"[]\") // read again after each commit\n\n  const look = (from: EventTarget | null) => {\n    const el = from instanceof Element ? from.closest<HTMLElement>(\"[data-slot=sidebar-link], [data-slot=sidebar-label]\") : null\n    target.current = el\n    const box = list.current\n    if (!el || !box || !ruler) return setPeek(null)\n    const r = el.getBoundingClientRect(), edge = box.getBoundingClientRect()\n    const rtl = getComputedStyle(box).direction === \"rtl\"\n    const link = el.dataset.slot === \"sidebar-link\"\n    setPeek({\n      key: link ? el.dataset.peekId! : \"\",\n      name: el.dataset.name ?? el.textContent ?? \"\",\n      group: link ? el.closest<HTMLElement>(\"[data-slot=sidebar-group]\")?.dataset.name ?? \"\" : \"\",\n      y: r.top + r.height / 2,\n      edge: rtl ? edge.left : edge.right,\n      rtl,\n    })\n  }\n\n  // The callout sits beside its tick, kept inside the window; the leader line reaches back to the tick.\n  React.useLayoutEffect(() => {\n    const el = callout.current\n    if (!el || !peek) return\n    const place = () => {\n      const name = el.querySelector<HTMLElement>(\"[data-slot=sidebar-callout-name]\")\n      const lead = name ? name.offsetTop + name.offsetHeight / 2 : 0\n      const top = Math.max(8, Math.min(peek.y - lead, innerHeight - el.offsetHeight - 8))\n      el.style.top = `${top}px`\n      el.style.setProperty(\"--leader\", `${peek.y - top}px`)\n    }\n    place()\n    const watch = new ResizeObserver(place)\n    watch.observe(el)\n    return () => watch.disconnect()\n  }, [peek])\n\n  return (\n    <nav\n      data-slot=\"sidebar\"\n      aria-label={label}\n      className={cn(\"ot-sidebar ot-scroll\", className)}\n      onScroll={(e) => {\n        onScroll?.(e)\n        if (target.current) look(target.current) // the tick moved under the pointer\n      }}\n      {...props}\n    >\n      {wide !== false && (\n        <PeekContext.Provider value={{ peek, slot, folded: !!ruler }}>\n          <div\n            ref={list}\n            data-slot=\"sidebar-list\"\n            data-folded={folded || undefined}\n            data-compact={compact || undefined}\n            data-variant={variant}\n            className=\"ot-sidebar-list\"\n            onPointerOver={(e) => {\n              if (e.pointerType === \"touch\") return\n              setHushed(false)\n              look(e.target)\n            }}\n            onPointerLeave={() => !list.current?.contains(document.activeElement) && look(null)}\n            onFocus={(e) => {\n              setHushed(false)\n              look(e.target.matches(\":focus-visible\") ? e.target : null)\n            }}\n            onBlur={(e) => !list.current?.contains(e.relatedTarget as Node | null) && look(null)}\n            onKeyDown={(e) => e.key === \"Escape\" && peek && setHushed(true)}\n          >\n            {children}\n          </div>\n          {ruler && peek && !hushed && (\n            <div\n              ref={callout}\n              key={peek.key || peek.name}\n              data-slot=\"sidebar-callout\"\n              data-rtl={peek.rtl || undefined}\n              aria-hidden=\"true\"\n              className=\"ot-sidebar-callout\"\n              style={peek.rtl ? { right: innerWidth - peek.edge } : { left: peek.edge }}\n            >\n              <p data-slot=\"sidebar-callout-name\" className=\"ot-sidebar-callout-name\">{peek.name}</p>\n              {peek.group ? <p className=\"ot-sidebar-callout-group\">{peek.group}</p> : null}\n              <div ref={setSlot} className=\"ot-sidebar-callout-preview\" />\n            </div>\n          )}\n        </PeekContext.Provider>\n      )}\n      <Sheet open={open} onOpenChange={setOpen}>\n        {wide !== true && (\n          <SheetTrigger asChild>\n            <Button variant=\"quiet\" data-slot=\"sidebar-trigger\">{sheetLabel}</Button>\n          </SheetTrigger>\n        )}\n        {wide === false && (\n          <SheetContent side=\"start\" className=\"ot-sidebar-sheet\">\n            <SheetSpine>{sheetLabel}</SheetSpine>\n            <SheetTitle className=\"ot-sr\">{sheetLabel}</SheetTitle>\n            <div\n              data-slot=\"sidebar-list\"\n              data-compact={compact || undefined}\n              data-variant={variant}\n              className=\"ot-sidebar-list\"\n              onClick={(e) => {\n                if ((e.target as Element).closest(\"a[href]\")) setOpen(false)\n              }}\n            >\n              {children}\n            </div>\n          </SheetContent>\n        )}\n      </Sheet>\n      <Scrollbar sections={JSON.parse(groups) as ScrollbarSection[]} />\n    </nav>\n  )\n}\n\n/** The column's own name, at the top. Folded, it too keeps its initial. */\nfunction SidebarHead({ className, children, ...props }: React.ComponentProps<\"p\">) {\n  return (\n    <p data-slot=\"sidebar-head\" className={cn(\"ot-sidebar-head\", className)} {...props}>\n      {fold(children)}\n    </p>\n  )\n}\n\ntype SidebarGroupProps = Omit<React.ComponentProps<\"div\">, \"aria-labelledby\"> & {\n  /** What the links share: a movement (\"VI Controls\"), a section. Folded, a leading roman numeral stays (\"VI\"), or else the initial. */\n  label: string\n}\n\nfunction SidebarGroup({ label, className, children, ...props }: SidebarGroupProps) {\n  const id = React.useId()\n  const { mark, rest, numeral } = split(label)\n  return (\n    <div data-slot=\"sidebar-group\" data-name={label} className={cn(\"ot-sidebar-group\", className)} {...props}>\n      <p id={id} data-slot=\"sidebar-label\" data-name={label} className=\"ot-sidebar-label\">\n        <bdi>\n          <span className=\"ot-sidebar-i\">{mark}</span>\n          {numeral ? \" \" : null}\n          <span className=\"ot-sidebar-rest\" data-numeral={numeral || undefined}>{rest}</span>\n        </bdi>\n      </p>\n      <ul aria-labelledby={id} className=\"ot-sidebar-links\">{children}</ul>\n    </div>\n  )\n}\n\ntype SidebarLinkProps = React.ComponentProps<\"a\"> & {\n  /** The page you are on: it carries the accent dot. */\n  current?: boolean\n  /** Render the child (a framework's Link) with the sidebar's look. */\n  asChild?: boolean\n  /** Shown beside the tick, under its name, while the column is folded and the link is pointed at or focused: a sentence about where it goes. */\n  preview?: React.ReactNode\n}\n\nfunction SidebarLink({ current, asChild = false, preview, className, children, ...props }: SidebarLinkProps) {\n  const Comp = asChild ? Slot : \"a\"\n  const id = React.useId()\n  const { peek, slot } = React.useContext(PeekContext)\n  // The word sits in its own box so folding can take it away and leave the name for assistive technology.\n  const word = (node: React.ReactNode) => <span className=\"ot-sidebar-text\">{node}</span>\n  const label = asChild && React.isValidElement<{ children?: React.ReactNode }>(children) ? React.cloneElement(children, undefined, word(children.props.children)) : word(children)\n  return (\n    <li data-slot=\"sidebar-item\" className=\"ot-sidebar-item\">\n      <Comp data-slot=\"sidebar-link\" data-peek-id={id} data-peeked={peek?.key === id || undefined} aria-current={current ? \"page\" : undefined} className={cn(\"ot-sidebar-link\", className)} {...props}>\n        {label}\n      </Comp>\n      {preview && slot && peek?.key === id ? createPortal(preview, slot) : null}\n    </li>\n  )\n}\n\nexport { Sidebar, SidebarHead, SidebarGroup, SidebarLink, type SidebarProps }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/0nlytype/styles/sidebar.css",
      "content": "@layer components {\n  /* ── ot-sidebar ── a column of words; folded, a ruler: each group keeps its numeral, each link a tick.\n     Wide, the words stand inline. Narrow, only the trigger shows and the same words open in a sheet.\n     860px is the docs frame's breakpoint and BREAKPOINT in sidebar.tsx: keep them equal.\n     The nav is the scroller (give it a height); its rail runs down the column's own rule. */\n  /* Registered, so each link's place is worked out on the link and inherited by its words. */\n  @property --ot-sidebar-i { syntax: \"<integer>\"; inherits: true; initial-value: 0; }\n  .ot-sidebar { font-size: var(--ot-mp); line-height: var(--ot-mp-lh); }\n  .ot-sidebar.ot-scroll { overflow-x: hidden; }\n  .ot-sidebar > .ot-scrollbar { --line: 0; } /* the thumb rides the column's own hairline */\n  .ot-sidebar-list {\n    display: grid; align-content: start; justify-items: start; gap: var(--ot-space-1);\n    font-size: var(--ot-mp); line-height: var(--ot-mp-lh);\n  }\n  /* Compact: a size down, and the links close up. */\n  .ot-sidebar-list[data-compact] { font-size: var(--ot-p); line-height: var(--ot-p-lh); }\n  .ot-sidebar-list[data-compact] :is(.ot-sidebar-group, .ot-sidebar-links) { gap: 0; }\n  .ot-sidebar-list[data-compact] :is(.ot-sidebar-group + .ot-sidebar-group, .ot-sidebar-head + .ot-sidebar-group) { margin-block-start: var(--ot-space-5); }\n  .ot-sidebar > .ot-sidebar-list { padding-inline-end: var(--ot-space-6); border-inline-end: var(--ot-hairline) solid var(--ot-rule); }\n  /* Before the browser has said how wide it is, both surfaces are in the page and CSS chooses. */\n  @media (min-width: 860px) { .ot-sidebar > [data-slot=\"sidebar-trigger\"] { display: none; } }\n  @media (max-width: 859.98px) { .ot-sidebar > .ot-sidebar-list { display: none; } }\n  .ot-sheet.ot-sidebar-sheet { width: min(20rem, calc(100vw - var(--ot-space-6))); }\n  .ot-sidebar-head { margin-block-end: var(--ot-space-4); font-weight: 600; color: var(--ot-ink); white-space: nowrap; }\n  .ot-sidebar-group { display: grid; justify-items: start; gap: var(--ot-space-1); }\n  .ot-sidebar-group + .ot-sidebar-group, .ot-sidebar-head + .ot-sidebar-group { margin-block-start: var(--ot-space-4); }\n  .ot-sidebar-label { font-size: var(--ot-pp); line-height: var(--ot-pp-lh); color: var(--ot-pencil); white-space: nowrap; font-variant-numeric: tabular-nums; transition: color var(--ot-allegro); }\n  .ot-sidebar-links { display: grid; justify-items: start; gap: var(--ot-space-1); margin: 0; padding: 0; list-style: none; }\n  .ot-sidebar-item { --ot-sidebar-i: sibling-index(); }\n  .ot-sidebar-link {\n    position: relative; display: flex; align-items: baseline; padding-inline-start: 1em;\n    color: var(--ot-graphite); text-decoration: none; white-space: nowrap; transition: color var(--ot-allegro);\n  }\n  .ot-sidebar-link:is(:hover, [data-force~=\"hover\"], [data-peeked]), .ot-sidebar-link[aria-current=\"page\"] { color: var(--ot-ink); }\n  .ot-sidebar-link::before {\n    content: \"\"; position: absolute; inset-inline-start: 0; top: calc(50% - 3px); width: 6px; height: 6px; border-radius: 50%;\n    background: var(--ot-accent); scale: 0;\n    transition: scale var(--ot-moderato) var(--ot-spiccato), background-color var(--ot-allegro), box-shadow var(--ot-allegro);\n  }\n  .ot-sidebar-link:is(:hover, [data-force~=\"hover\"], [data-peeked]):not([aria-current=\"page\"])::before { scale: 1; background-color: transparent; box-shadow: inset 0 0 0 var(--ot-hairline) var(--ot-rule-strong); }\n  .ot-sidebar-link[aria-current=\"page\"]::before { scale: 1; }\n\n  /* Folding: the words fold away in turn, and what is left is a ruler. The name stays in the page for assistive technology. */\n  .ot-sidebar-text, .ot-sidebar-rest {\n    display: inline-block; overflow: clip; width: auto; vertical-align: bottom;\n    transition: width var(--ot-andante) var(--ot-exhale), opacity var(--ot-moderato); transition-delay: calc(var(--ot-sidebar-i) * var(--ot-arpeggio));\n  }\n  .ot-sidebar-list[data-folded] :is(.ot-sidebar-text, .ot-sidebar-rest) { width: 0; opacity: 0; }\n  .ot-sidebar-list[data-folded] .ot-sidebar-head { color: var(--ot-ink); }\n\n  /* The ruler: a hairline down the column's inline end, a numeral for each group, a tick for each link.\n     The tick stretches when pointed at; the page you are on has the longest, with the dot at its far end. */\n  .ot-sidebar > .ot-sidebar-list[data-folded] { inline-size: var(--ot-sidebar-rail, 3rem); padding-inline-end: 0; justify-items: stretch; }\n  .ot-sidebar-list[data-folded] :is(.ot-sidebar-group, .ot-sidebar-links) { justify-items: stretch; }\n  .ot-sidebar-list[data-folded][data-compact] :is(.ot-sidebar-group + .ot-sidebar-group, .ot-sidebar-head + .ot-sidebar-group) { margin-block-start: var(--ot-space-3); }\n  .ot-sidebar-list[data-folded] .ot-sidebar-label { padding-inline-start: var(--ot-space-1); }\n  .ot-sidebar-list[data-folded] .ot-sidebar-group:has([aria-current=\"page\"]) .ot-sidebar-label { color: var(--ot-ink); }\n  .ot-sidebar-link::after {\n    content: \"\"; position: absolute; inset-inline-end: 0; top: 50%; width: 0; height: var(--ot-hairline); background: var(--ot-rule-strong);\n    transition: width var(--ot-moderato) var(--ot-exhale), background-color var(--ot-allegro); transition-delay: calc(var(--ot-sidebar-i) * var(--ot-arpeggio)), 0s;\n  }\n  .ot-sidebar-list[data-folded] .ot-sidebar-link {\n    --tick: 0.5rem; inline-size: 100%; min-block-size: 1.5rem; padding-inline: 0; align-items: center;\n  }\n  .ot-sidebar-list[data-folded] .ot-sidebar-link::after { width: var(--tick); }\n  .ot-sidebar-list[data-folded] .ot-sidebar-link:is(:hover, [data-force~=\"hover\"], [data-peeked], [aria-current=\"page\"]) { --tick: 1rem; }\n  .ot-sidebar-list[data-folded] .ot-sidebar-link:is(:hover, [data-force~=\"hover\"], [data-peeked], [aria-current=\"page\"])::after { background: var(--ot-ink); }\n  .ot-sidebar-list[data-folded] .ot-sidebar-link::before { inset-inline: auto calc(var(--tick) - 3px); transition-property: scale, background-color, box-shadow, inset-inline-end; }\n  .ot-sidebar-list[data-folded] .ot-sidebar-link:focus-visible { outline-offset: -2px; }\n\n  /* chapter: a book's running contents, which open only the chapter you are reading. The group holding the page you\n     are on stands open; the others keep only their names. A still pointer opens one, and focus opens it at once, so\n     every link stays in the tab order and in the page for assistive technology. Unfolded only. */\n  .ot-sidebar-list[data-variant=\"chapter\"]:not([data-folded]) .ot-sidebar-links {\n    --wait: 0s; overflow: clip;\n    transition: block-size var(--ot-andante) var(--ot-exhale) var(--wait), opacity var(--ot-moderato) var(--wait);\n  }\n  .ot-sidebar-list[data-variant=\"chapter\"]:not([data-folded]) .ot-sidebar-group:hover .ot-sidebar-links { --wait: 240ms; }\n  .ot-sidebar-list[data-variant=\"chapter\"]:not([data-folded]) .ot-sidebar-group:not(:has([aria-current=\"page\"]), :hover, :focus-within, [data-force~=\"hover\"]) .ot-sidebar-links { block-size: 0; opacity: 0; }\n  .ot-sidebar-list[data-variant=\"chapter\"]:not([data-folded]) .ot-sidebar-group:has([aria-current=\"page\"]) .ot-sidebar-label { color: var(--ot-ink); }\n  .ot-sidebar-list[data-variant=\"chapter\"]:not([data-folded]) .ot-sidebar-group:is(:hover, :focus-within, [data-force~=\"hover\"]):not(:has([aria-current=\"page\"])) .ot-sidebar-label { color: var(--ot-graphite); }\n\n  /* numerals: \"14 Where my feet stand, 08 there i take a photo\". Each group's place (01, 02) stands large in the\n     margin, in pencil (ink for the group you are in or point into); its label (a roman numeral and all) and its links\n     sit small beside it, from the numeral's cap height. The numerals share one column, so they align. Unfolded only. */\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) { grid-template-columns: max-content minmax(0, 1fr); column-gap: var(--ot-space-5); counter-reset: ot-sidebar-g; }\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) > :not(.ot-sidebar-group) { grid-column: 1 / -1; }\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) .ot-sidebar-group {\n    grid-column: 1 / -1; grid-template-columns: subgrid; grid-template-rows: auto 1fr; column-gap: var(--ot-space-5); justify-self: stretch; counter-increment: ot-sidebar-g;\n  }\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) :is(.ot-sidebar-label, .ot-sidebar-links) { grid-column: 2; }\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) .ot-sidebar-group::before {\n    content: counter(ot-sidebar-g, decimal-leading-zero) / \"\"; grid-column: 1; grid-row: 1 / span 2; margin-block-start: -0.06em;\n    font-size: var(--ot-f); line-height: 0.82; letter-spacing: -0.04em; font-weight: 300; color: var(--ot-pencil); font-variant-numeric: tabular-nums lining-nums;\n    transition: color var(--ot-moderato) var(--ot-breath);\n  }\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) .ot-sidebar-group:is(:has([aria-current=\"page\"]), :hover, [data-force~=\"hover\"])::before { color: var(--ot-ink); }\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) .ot-sidebar-links { gap: 0; }\n  .ot-sidebar-list[data-variant=\"numerals\"]:not([data-folded]) .ot-sidebar-link { font-size: var(--ot-p); line-height: var(--ot-p-lh); }\n  @media (forced-colors: active) { .ot-sidebar-list[data-variant=\"numerals\"] .ot-sidebar-group::before { color: CanvasText; } }\n\n  /* The name comes out into the margin on a leader line, with what the link is beneath it. It is one element,\n     placed by the script beside whatever is pointed at; it never takes the pointer. */\n  .ot-sidebar-callout {\n    position: fixed; z-index: 45; display: grid; justify-items: start; gap: 0.2rem; inline-size: max-content; max-inline-size: min(22rem, 60vw);\n    padding: 0.2rem var(--ot-space-3) 0.4rem var(--ot-space-6); background: var(--ot-paper); pointer-events: none;\n    font-size: var(--ot-pp); line-height: var(--ot-pp-lh); color: var(--ot-graphite);\n  }\n  .ot-sidebar-callout::before {\n    content: \"\"; position: absolute; inset-inline-start: 0; top: var(--leader, 0.9rem); width: var(--ot-space-5); height: var(--ot-hairline); background: var(--ot-ink);\n    transform-origin: 0 50%; animation: ot-draw-x var(--ot-allegro) var(--ot-exhale) backwards;\n  }\n  .ot-sidebar-callout:is([dir=\"rtl\"], [dir=\"rtl\"] *)::before, .ot-sidebar-callout[data-rtl]::before { transform-origin: 100% 50%; }\n  .ot-sidebar-callout-name { font-size: var(--ot-mp); line-height: var(--ot-mp-lh); letter-spacing: var(--ot-mp-tr); font-weight: 400; color: var(--ot-ink); white-space: nowrap; }\n  .ot-sidebar-callout-group { color: var(--ot-pencil); font-variant-numeric: tabular-nums; }\n  .ot-sidebar-callout-preview:not(:empty) { max-inline-size: 30ch; margin-block-start: 0.2rem; animation: ot-arrive var(--ot-moderato) var(--ot-exhale) 380ms backwards; }\n}\n",
      "type": "registry:file",
      "target": "styles/0nlytype/sidebar.css"
    }
  ],
  "css": {
    "@import \"../styles/0nlytype/sidebar.css\"": {}
  },
  "meta": {
    "movement": "VIII",
    "underneath": "hook",
    "contract": "ot-sidebar"
  },
  "type": "registry:ui"
}
