{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "popover",
  "title": "Popover",
  "description": "A panel hung from what opened it, on a leader line. Escape or a click elsewhere puts it away.",
  "dependencies": [
    "@radix-ui/react-popover"
  ],
  "registryDependencies": [
    "https://thedirectors.agency/ui/r/0nlytype.json"
  ],
  "files": [
    {
      "path": "registry/0nlytype/ui/popover.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n  return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n  return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n  return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />\n}\n\nfunction PopoverClose(props: React.ComponentProps<typeof PopoverPrimitive.Close>) {\n  return <PopoverPrimitive.Close data-slot=\"popover-close\" {...props} />\n}\n\ntype Variant = \"leader\" | \"brace\" | \"cut\"\n\n/* Each variant hangs the panel its own distance off: the leader's length, the brace's small gap\n   (Radix adds the brace's own height), and nothing at all for the cut, which rides over its opener. */\nconst OFFSET: Record<Variant, number> = { leader: 27 /* --ot-space-5 */, brace: 6, cut: 0 }\n\n/**\n * A panel hung from what opened it. leader (the default): on a leader line, which joins the panel to\n * the trigger when it sits above or below and aligns to an edge (the default is the trigger's start\n * edge). brace: the panel's width gathered by a brace to one point at the trigger. cut: the panel's\n * edge cuts through the trigger's words and the panel rides over their lower half. Other menus and\n * pickers wear the same `ot-pop` panel.\n */\nfunction PopoverContent({\n  className,\n  variant = \"leader\",\n  align = variant === \"brace\" ? \"center\" : \"start\",\n  sideOffset = OFFSET[variant],\n  collisionPadding = 20,\n  arrowPadding = 24,\n  style,\n  children,\n  ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content> & { variant?: Variant }) {\n  return (\n    <PopoverPrimitive.Portal>\n      <PopoverPrimitive.Content\n        data-slot=\"popover-content\"\n        data-variant={variant === \"leader\" ? undefined : variant}\n        align={align}\n        sideOffset={sideOffset}\n        collisionPadding={collisionPadding}\n        arrowPadding={arrowPadding}\n        style={{ \"--ot-pop-gap\": `${sideOffset}px`, ...style } as React.CSSProperties}\n        className={cn(\"ot-pop\", className)}\n        {...props}\n      >\n        {children}\n        {variant === \"brace\" && (\n          // The brace's two ends curl at the panel's corners; its point is Radix's arrow, which Radix\n          // keeps over the trigger's middle even when the panel shifts to stay on screen.\n          <span className=\"ot-pop-brace\" aria-hidden=\"true\">\n            <span className=\"ot-pop-brace-arms\">\n              <PopoverPrimitive.Arrow asChild>\n                <span className=\"ot-pop-brace-point\" />\n              </PopoverPrimitive.Arrow>\n            </span>\n          </span>\n        )}\n      </PopoverPrimitive.Content>\n    </PopoverPrimitive.Portal>\n  )\n}\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, PopoverClose }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/0nlytype/styles/popover.css",
      "content": "@layer components {\n  /* ── ot-pop ── popover: a panel hung from what opened it, on a leader line.\n     Keyed on the class and [data-state] alone, so the menus and pickers that\n     wear ot-pop (dropdown menu, combobox, date picker) hang the same way.\n     Radix places it (side, align, sideOffset); --ot-pop-gap is that offset. */\n  .ot-pop {\n    --ot-pop-gap: 8px; --ot-pop-lead: 1.1em;\n    position: relative; z-index: 50; padding: var(--ot-space-4) var(--ot-space-5); overflow: visible;\n    max-width: min(26rem, calc(100vw - 2 * var(--ot-margin)));\n    background: var(--ot-paper); color: var(--ot-graphite); box-shadow: inset 0 0 0 var(--ot-hairline) var(--ot-rule-strong);\n    outline: 0;\n    animation: ot-pop-in var(--ot-moderato) var(--ot-exhale);\n  }\n  .ot-pop[data-state=\"closed\"] { animation: ot-pop-out var(--ot-allegro) var(--ot-breath) forwards; }\n  .ot-pop[data-side=\"top\"] { --ot-pop-from: 4px; }\n  @keyframes ot-pop-in { from { opacity: 0; translate: 0 var(--ot-pop-from, -4px); } }\n  @keyframes ot-pop-out { to { opacity: 0; } }\n\n  /* The leader: a dot on the trigger's edge and a line dropping to the panel. */\n  .ot-pop:is([data-side=\"bottom\"], [data-side=\"top\"])::before,\n  .ot-pop:is([data-side=\"bottom\"], [data-side=\"top\"])::after { content: \"\"; position: absolute; pointer-events: none; }\n  .ot-pop:is([data-side=\"bottom\"], [data-side=\"top\"])::before { inset-inline-start: var(--ot-pop-lead); width: var(--ot-hairline); height: var(--ot-pop-gap); background: var(--ot-ink); }\n  .ot-pop:is([data-side=\"bottom\"], [data-side=\"top\"])::after { inset-inline-start: calc(var(--ot-pop-lead) - 2px); width: 5px; height: 5px; border-radius: 50%; background: var(--ot-ink); }\n  .ot-pop[data-align=\"end\"] { --ot-pop-lead: calc(100% - 1.1em); }\n  .ot-pop[data-align=\"center\"] { --ot-pop-lead: 50%; }\n  .ot-pop[data-side=\"bottom\"]::before { bottom: 100%; transform-origin: 50% 0; }\n  .ot-pop[data-side=\"bottom\"]::after { bottom: calc(100% + var(--ot-pop-gap) - 2.5px); }\n  .ot-pop[data-side=\"top\"]::before { top: 100%; transform-origin: 50% 100%; }\n  .ot-pop[data-side=\"top\"]::after { top: calc(100% + var(--ot-pop-gap) - 2.5px); }\n  .ot-pop[data-state=\"open\"]::after { animation: ot-land var(--ot-moderato) var(--ot-spiccato) backwards; }\n  .ot-pop[data-state=\"open\"]::before { animation: ot-draw-y var(--ot-moderato) var(--ot-breath) 60ms backwards; }\n\n  /* Forced colours drop the panel's hairline (a box-shadow) and paint the leader's background away. */\n  @media (forced-colors: active) {\n    /* The hairline is a box-shadow, which forced colours drop. A border, not an outline: Radix's menus\n       set an inline outline: none on their panel, which no stylesheet can outrank. */\n    .ot-pop { border: var(--ot-hairline) solid CanvasText; }\n    .ot-pop::before, .ot-pop::after { forced-color-adjust: none; background: CanvasText; }\n    .ot-pop[data-variant=\"brace\"] { border: 0; } /* boxless: its brace is the edge */\n  }\n\n  /* ── brace ── the panel's width gathered to one point at the trigger, like the brace that joins a\n     score's staves or an underbrace that sums a span. The ends curl at the panel's corners (this\n     element's own ::before and ::after); the arms and the point are Radix's arrow, which Radix keeps\n     over the trigger's middle when the panel shifts (it measures from .ot-pop-brace-arms, which is centred\n     on the panel, so no correction is needed). The arms run long and .ot-pop-brace-arms clips\n     them where the curls begin. Drawn as for a panel above; Radix turns the point over for one below. */\n  .ot-pop[data-variant=\"brace\"] {\n    --ot-pop-brace-r: var(--ot-space-2); --ot-pop-brace-g: var(--ot-space-2); --ot-pop-brace-in: var(--ot-space-5);\n    padding: var(--ot-space-3) var(--ot-pop-brace-in) var(--ot-space-4); box-shadow: none; /* the brace is the panel's edge */\n  }\n  .ot-pop:is([data-variant=\"brace\"], [data-variant=\"cut\"])::before,\n  .ot-pop:is([data-variant=\"brace\"], [data-variant=\"cut\"])::after { content: none; }\n  .ot-pop-brace, .ot-pop-brace-arms { position: absolute; inset-block: 0; pointer-events: none; }\n  .ot-pop-brace { inset-inline: var(--ot-pop-brace-in); } /* spans the words, not the paper round them */\n  .ot-pop-brace-arms { left: var(--ot-pop-brace-r); right: var(--ot-pop-brace-r); overflow-x: clip; overflow-y: visible; clip-path: inset(-3em 0); }\n  .ot-pop-brace-point { position: relative; width: 0; height: calc(var(--ot-pop-brace-g) + 2 * var(--ot-pop-brace-r)); }\n  .ot-pop-brace::before, .ot-pop-brace::after,\n  .ot-pop-brace-point::before, .ot-pop-brace-point::after { content: \"\"; position: absolute; border: 0 solid var(--ot-ink); }\n  .ot-pop-brace-point::before, .ot-pop-brace-point::after {\n    top: calc(var(--ot-pop-brace-g) + var(--ot-pop-brace-r) - var(--ot-hairline)); width: 100vw; height: calc(var(--ot-pop-brace-r) + var(--ot-hairline));\n    border-top-width: var(--ot-hairline);\n  }\n  .ot-pop-brace-point::before { right: 0; border-right-width: var(--ot-hairline); border-top-right-radius: var(--ot-pop-brace-r); }\n  .ot-pop-brace-point::after { left: 0; border-left-width: var(--ot-hairline); border-top-left-radius: var(--ot-pop-brace-r); }\n  .ot-pop-brace::before, .ot-pop-brace::after { width: var(--ot-pop-brace-r); height: var(--ot-pop-brace-r); }\n  .ot-pop-brace::before { left: 0; border-left-width: var(--ot-hairline); }\n  .ot-pop-brace::after { right: 0; border-right-width: var(--ot-hairline); }\n  .ot-pop[data-side=\"bottom\"] .ot-pop-brace::before, .ot-pop[data-side=\"bottom\"] .ot-pop-brace::after { top: calc(-1 * (var(--ot-pop-brace-g) + var(--ot-pop-brace-r))); border-top-width: var(--ot-hairline); }\n  .ot-pop[data-side=\"top\"] .ot-pop-brace::before, .ot-pop[data-side=\"top\"] .ot-pop-brace::after { top: calc(100% + var(--ot-pop-brace-g)); border-bottom-width: var(--ot-hairline); }\n  .ot-pop[data-side=\"bottom\"] .ot-pop-brace::before { border-top-left-radius: var(--ot-pop-brace-r); }\n  .ot-pop[data-side=\"bottom\"] .ot-pop-brace::after { border-top-right-radius: var(--ot-pop-brace-r); }\n  .ot-pop[data-side=\"top\"] .ot-pop-brace::before { border-bottom-left-radius: var(--ot-pop-brace-r); }\n  .ot-pop[data-side=\"top\"] .ot-pop-brace::after { border-bottom-right-radius: var(--ot-pop-brace-r); }\n  .ot-pop[data-variant=\"brace\"]:is([data-side=\"left\"], [data-side=\"right\"]) .ot-pop-brace { display: none; } /* a brace gathers a width; beside the trigger there's none to gather */\n  /* Gather: the arms open out from the middle to the panel's ends, then the ends curl in. */\n  .ot-pop[data-state=\"open\"] .ot-pop-brace-arms { animation: ot-pop-brace-open var(--ot-moderato) var(--ot-exhale) backwards; }\n  .ot-pop[data-state=\"open\"] .ot-pop-brace::before, .ot-pop[data-state=\"open\"] .ot-pop-brace::after { animation: ot-pop-out var(--ot-allegro) var(--ot-breath) reverse var(--ot-moderato) backwards; }\n  @keyframes ot-pop-brace-open { from { clip-path: inset(-3em 50%); } }\n\n  /* ── cut ── the panel's edge cuts through the trigger's words at half their height and rides over\n     the lower half, the way SPECTRA's title is cut by a line. There is no leader: the join is the cut.\n     Radix gives the trigger's height; the edge the words are cut by is set in ink. */\n  .ot-pop[data-variant=\"cut\"] { --ot-pop-from: 0px; --ot-pop-cut: calc(var(--radix-popover-trigger-height, 0px) / 2); }\n  .ot-pop[data-variant=\"cut\"][data-side=\"bottom\"] { translate: 0 calc(-1 * var(--ot-pop-cut)); box-shadow: inset 0 var(--ot-hairline) var(--ot-ink), inset 0 0 0 var(--ot-hairline) var(--ot-rule-strong); }\n  .ot-pop[data-variant=\"cut\"][data-side=\"top\"] { translate: 0 var(--ot-pop-cut); box-shadow: inset 0 calc(-1 * var(--ot-hairline)) var(--ot-ink), inset 0 0 0 var(--ot-hairline) var(--ot-rule-strong); }\n  .ot-pop[data-variant=\"cut\"][data-state=\"open\"] { animation-duration: var(--ot-andante); }\n}\n",
      "type": "registry:file",
      "target": "styles/0nlytype/popover.css"
    }
  ],
  "css": {
    "@import \"../styles/0nlytype/popover.css\"": {}
  },
  "meta": {
    "movement": "IX",
    "underneath": "radix",
    "contract": "ot-pop"
  },
  "type": "registry:ui"
}
