{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toggle",
  "title": "Toggle",
  "description": "A word you can hold down. Held, it's yours and turns italic: under a fermata's arc and dot, behind a pen that inks the tenuto's line, with a small note hung beside it, or set on its drawn guides.",
  "dependencies": [
    "@radix-ui/react-toggle"
  ],
  "registryDependencies": [
    "https://thedirectors.agency/ui/r/0nlytype.json"
  ],
  "files": [
    {
      "path": "registry/0nlytype/ui/toggle.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\"\n\nimport { useComposedRefs } from \"@/lib/0nlytype/refs\"\nimport { cn } from \"@/lib/utils\"\n\ntype ToggleProps = Omit<React.ComponentProps<typeof TogglePrimitive.Root>, \"asChild\"> & {\n  /**\n   * The sign a held word wears. fermata: an arc is sketched over the word, a dot lands under it, and the word\n   * leans into the italic. tenuto: a pen runs along a line under the word and rewrites it in the italic as it passes.\n   * aside: a small note in our voice is hung beside the held word on a hairline arrow. guides: the two lines the word\n   * is set on, baseline and x-height, are drawn through it in dots.\n   */\n  variant?: \"fermata\" | \"tenuto\" | \"aside\" | \"guides\"\n  /** aside only: what the note beside the held word says. */\n  note?: string\n  /** Pins a state for documentation (\"hover\", \"focus\"); set on the root. */\n  \"data-force\"?: string\n}\n\n/**\n * The word and its italic copy start at the same edge but aren't the same width, so a mark centred on\n * the button would sit off the word you see. This reads both widths (--ot-toggle-r, --ot-toggle-i) and\n * the stylesheet centres or ends the marks on whichever face is showing. Fonts arriving and resizes put\n * the marks straight there (data-still); only a press moves them.\n */\nfunction useFaces(variant: string, children: React.ReactNode) {\n  const ref = React.useRef<HTMLButtonElement | null>(null)\n  React.useLayoutEffect(() => {\n    const button = ref.current\n    const label = button?.firstElementChild as HTMLElement | null\n    const roman = label?.firstElementChild as HTMLElement | null\n    if (!button || !label?.dataset.text || !roman || variant === \"tenuto\") return\n    // The face's own width: its box less the overhang (--over) it keeps on each side, whatever the box-sizing.\n    const width = (cs: CSSStyleDeclaration) =>\n      `${parseFloat(cs.width) - (cs.boxSizing === \"border-box\" ? parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight) : 0)}px`\n    const read = () => {\n      button.setAttribute(\"data-still\", \"\")\n      button.style.setProperty(\"--ot-toggle-r\", width(getComputedStyle(roman)))\n      button.style.setProperty(\"--ot-toggle-i\", width(getComputedStyle(label, \"::after\")))\n      void button.offsetWidth\n      button.removeAttribute(\"data-still\")\n    }\n    read()\n    const resize = new ResizeObserver(read)\n    resize.observe(label)\n    resize.observe(roman)\n    return () => resize.disconnect()\n  }, [variant, children])\n  return ref\n}\n\n/**\n * A word you can hold down: a native button with aria-pressed. Held, the word is yours, so it turns italic.\n * The label shares its grid cell with an italic copy of itself (drawn by the stylesheet from data-text),\n * so the button is always as wide as its wider state and nothing beside it moves.\n */\nfunction Toggle({ className, variant = \"fermata\", note = \"on\", children, ref, ...props }: ToggleProps) {\n  const ownRef = useFaces(variant, children)\n  const composedRef = useComposedRefs(ownRef, ref)\n  return (\n    <TogglePrimitive.Root\n      ref={composedRef}\n      data-slot=\"toggle\"\n      data-variant={variant}\n      className={cn(\"ot-toggle\", className)}\n      {...props}\n    >\n      <span className=\"ot-toggle-label\" data-text={typeof children === \"string\" ? children : undefined}>\n        <span>{children}</span>\n        {variant === \"aside\" ? (\n          <small className=\"ot-toggle-note\" aria-hidden=\"true\">\n            <span className=\"ot-toggle-arrow\" />\n            {note}\n          </small>\n        ) : null}\n      </span>\n    </TogglePrimitive.Root>\n  )\n}\n\nexport { Toggle, type ToggleProps }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/0nlytype/styles/toggle.css",
      "content": "@layer components {\n  /* How much of the mark is drawn, 0 to 1: the fermata's arc, or the tenuto's pencil line. */\n  @property --ot-toggle-draw { syntax: \"<number>\"; inherits: true; initial-value: 0; }\n  /* How far the pen has rewritten the word, 0 to 1: the tenuto's ink line and its italic. */\n  @property --ot-toggle-ink { syntax: \"<number>\"; inherits: true; initial-value: 0; }\n\n  /* ── ot-toggle ── a word you can hold down. Held, it's yours, so it turns italic: under the fermata, or over the tenuto.\n     Marks pass through. --e anchors a mark at its start (0) while it draws and at its end (1) while it leaves, so a stroke\n     always travels the way you read; it flips only when the mark is whole or gone, so the flip never shows. --ie does the\n     same for the tenuto's ink. Both variants share one box, room for the arc above and the line below, so a fermata\n     and a tenuto side by side stand on one baseline. */\n  .ot-toggle {\n    --dir: 1; --e: 1; --ie: 1; --y: 0.3em;\n    --w: var(--ot-toggle-r, 100%); /* the width of the face you see: the roman, or held, the italic (measured by toggle.tsx) */\n    position: relative; appearance: none; border: 0; background: none; margin: 0; padding: 0.8em 0 var(--y);\n    font: inherit; color: var(--ot-graphite); cursor: pointer; -webkit-tap-highlight-color: transparent;\n    transition: color var(--ot-allegro), font-weight var(--ot-andante) var(--ot-exhale), font-stretch var(--ot-andante) var(--ot-exhale), --ot-toggle-draw var(--ot-moderato) var(--ot-exhale), --ot-toggle-ink var(--ot-andante) var(--ot-breath);\n  }\n  .ot-toggle:is([dir=\"rtl\"], [dir=\"rtl\"] *) { --dir: -1; }\n  .ot-toggle:is(:hover, [data-force~=\"hover\"]):not(:disabled) { color: var(--ot-ink); }\n  .ot-toggle:is(:hover, [data-force~=\"hover\"]):not(:disabled), .ot-toggle[data-state=\"on\"] { --ot-toggle-draw: 1; --e: 0; }\n  .ot-toggle[data-state=\"on\"] { --ot-toggle-ink: 1; --ie: 0; --w: var(--ot-toggle-i, 100%); color: var(--ot-ink); }\n  .ot-toggle:disabled { color: var(--ot-pencil); opacity: 0.55; cursor: not-allowed; }\n\n  /* The word and its italic copy share one cell, so the button is as wide as its wider state. Each overhangs the cell by\n     --over on every side, so a mask over it never trims the italic's swashes, and the pen's line can run past the ends. */\n  .ot-toggle-label { --over: 0.15em; display: inline-grid; align-items: baseline; white-space: nowrap; text-align: start; } /* the word stands where its label does */\n  .ot-toggle-label > span, .ot-toggle-label::after {\n    grid-area: 1 / 1; padding: var(--over); margin: calc(var(--over) * -1); transform-origin: 0 calc(100% - var(--over) - 0.25em);\n    transition: opacity var(--ot-moderato) var(--ot-breath), transform var(--ot-moderato) var(--ot-exhale), color var(--ot-allegro);\n  }\n  .ot-toggle-label::after {\n    content: attr(data-text) / \"\";\n    --over: calc(0.15em / var(--ot-expression-scale)); /* the same length as the word's, in the italic's larger em */\n    font-family: var(--ot-expression); font-style: italic; font-weight: 400; font-size: calc(var(--ot-expression-scale) * 1em); line-height: 1;\n    color: var(--ot-ink); opacity: 0; transform: skewX(12deg);\n  }\n  /* Apart from the tenuto, whose pen wipes the whole cell, each face keeps its own width, so the marks can find it. */\n  .ot-toggle:not([data-variant=\"tenuto\"]) > .ot-toggle-label > span, .ot-toggle:not([data-variant=\"tenuto\"]) > .ot-toggle-label::after { justify-self: start; }\n  /* A label that holds elements has no copy; it turns italic in place. */\n  .ot-toggle[data-state=\"on\"] > .ot-toggle-label:not([data-text]) > span { font-family: var(--ot-expression); font-style: italic; font-size: calc(var(--ot-expression-scale) * 1em); }\n\n  .ot-toggle::before, .ot-toggle::after { content: \"\"; position: absolute; pointer-events: none; }\n  /* Measuring (fonts arriving, a resize) isn't a choice: the marks go straight there. */\n  .ot-toggle[data-still], .ot-toggle[data-still]::before, .ot-toggle[data-still]::after,\n  .ot-toggle[data-still] *, .ot-toggle[data-still] *::before, .ot-toggle[data-still] *::after { transition: none; }\n\n  /* ── fermata (the default): the sign for a note held longer than written.\n     Pointing sketches the arc in pencil from its start foot; held, it inks, the dot lands under it, and the word\n     leans into the italic: the roman shears forward as it fades, and the italic arrives upright and settles into its slant. */\n  /* The sign stands over the middle of the face you see, so it slides over as the word leans into its wider or narrower italic. */\n  .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))::before, .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))::after { inset-inline-start: calc(var(--w) / 2); }\n  .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))::before {\n    top: 0; width: 1em; height: 0.5em; margin-inline-start: -0.5em; box-sizing: border-box;\n    border: var(--ot-hairline) solid var(--ot-rule-strong); border-bottom: 0; border-radius: 0.5em 0.5em 0 0;\n    scale: var(--dir) 1; /* drawn from the start foot, which is the right one right to left */\n    mask: conic-gradient(from -90deg at 50% 100%, #0000 calc(var(--e) * (1 - var(--ot-toggle-draw)) * 180deg), #000 0 calc((var(--e) * (1 - var(--ot-toggle-draw)) + var(--ot-toggle-draw)) * 180deg), #0000 0);\n    transition: border-color var(--ot-allegro), border-width var(--ot-allegro), translate var(--ot-moderato) var(--ot-spiccato), inset-inline-start var(--ot-moderato) var(--ot-exhale);\n  }\n  .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))::after {\n    --dot: max(0.24em, 4px);\n    top: calc(0.5em - var(--dot) * 1.15); width: var(--dot); height: var(--dot); margin-inline-start: calc(var(--dot) / -2); border-radius: 50%;\n    background: var(--ot-ink); scale: 0; translate: 0 -0.3em;\n    transition: scale var(--ot-allegro) var(--ot-breath), translate var(--ot-allegro) var(--ot-breath), inset-inline-start var(--ot-moderato) var(--ot-exhale);\n  }\n  .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))[data-state=\"on\"]::before { border-color: var(--ot-ink); border-width: var(--ot-stroke); }\n  .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))[data-state=\"on\"]::after { /* the arc arrives, then the dot lands */\n    scale: 1; translate: none;\n    transition: scale var(--ot-moderato) var(--ot-spiccato) calc(var(--ot-moderato) * 0.45), translate var(--ot-moderato) var(--ot-spiccato) calc(var(--ot-moderato) * 0.45), inset-inline-start var(--ot-moderato) var(--ot-exhale);\n  }\n  .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant])):active:not(:disabled)::before { translate: 0 0.12em; transition-duration: var(--ot-allegro); } /* pressed, the sign comes down toward the word */\n  /* The lean, for every variant but the tenuto: the face going out fades fast and the one coming in takes its time,\n     so the two are seldom seen at once. */\n  .ot-toggle:not([data-variant=\"tenuto\"]) > .ot-toggle-label::after,\n  .ot-toggle:not([data-variant=\"tenuto\"])[data-state=\"on\"] > .ot-toggle-label[data-text] > span { transition-duration: var(--ot-allegro), var(--ot-moderato), var(--ot-allegro); }\n  .ot-toggle:not([data-variant=\"tenuto\"])[data-state=\"on\"] > .ot-toggle-label[data-text] > span { opacity: 0; transform: skewX(-12deg); }\n  .ot-toggle:not([data-variant=\"tenuto\"])[data-state=\"on\"] > .ot-toggle-label::after { opacity: 1; transform: none; transition-duration: var(--ot-moderato); }\n\n  /* ── tenuto: the line under a note held its full value. Pointing sketches it in pencil. Held, a pen inks it from the\n     start, and behind the pen the word is rewritten in the italic. Released, the pen passes again, the ink leaves ahead\n     of it and the roman comes back behind it. The line, the pen and both masks read one number, so they never part. */\n  .ot-toggle[data-variant=\"tenuto\"]::before {\n    inset-inline: -0.15em; bottom: calc(var(--y) - var(--ot-stroke) / 2); height: var(--ot-stroke);\n    background:\n      linear-gradient(var(--ot-ink) 0 0) no-repeat calc((0.5 + (var(--ie) - 0.5) * var(--dir)) * 100%) 0 / calc(var(--ot-toggle-ink) * 100%) 100%,\n      linear-gradient(var(--ot-rule-strong) 0 0) no-repeat calc((0.5 + (var(--e) - 0.5) * var(--dir)) * 100%) 100% / calc(var(--ot-toggle-draw) * 100%) var(--ot-hairline);\n  }\n  .ot-toggle[data-variant=\"tenuto\"]::after { /* the pen: where the ink has reached, coming or going, seen only while it moves */\n    --dot: max(0.2em, 4px);\n    inset-inline-start: calc(-0.15em + (100% + 0.3em) * (var(--ie) + var(--ot-toggle-ink) * (1 - 2 * var(--ie)))); bottom: calc(var(--y) - var(--dot) / 2);\n    width: var(--dot); height: var(--dot); margin-inline-start: calc(var(--dot) / -2); border-radius: 50%;\n    background: var(--ot-ink); opacity: clamp(0, 12 * var(--ot-toggle-ink) * (1 - var(--ot-toggle-ink)), 1);\n  }\n  .ot-toggle[data-variant=\"tenuto\"] > .ot-toggle-label[data-text] > span { mask: linear-gradient(#000 0 0) no-repeat calc((0.5 - (var(--ie) - 0.5) * var(--dir)) * 100%) 0 / calc((1 - var(--ot-toggle-ink)) * 100%) 100%; }\n  .ot-toggle[data-variant=\"tenuto\"] > .ot-toggle-label::after { opacity: 1; transform: none; mask: linear-gradient(#000 0 0) no-repeat calc((0.5 + (var(--ie) - 0.5) * var(--dir)) * 100%) 0 / calc(var(--ot-toggle-ink) * 100%) 100%; }\n\n  /* ── aside: after \"It has to be design.\", where a small note in the roman is tucked into the italic's shoulder on a\n     hairline arrow. Held, the word is yours and leans into the italic; beside it, in our voice, the note says what that\n     means. It stands on the word's baseline, under an arrow that points back at the word. Pointing\n     sketches the arrow in pencil, reaching toward the word; held, it inks, its head lands and the note writes in.\n     The note hangs into the space after the word, like a margin note: it takes no room, so leave it some. */\n  .ot-toggle-note {\n    --gap: 0.45em; --len: 2.6em;\n    grid-area: 1 / 1; align-self: baseline; justify-self: start; width: 0; white-space: nowrap; pointer-events: none;\n    margin-inline: calc(var(--w) + var(--gap)) calc(-1 * (var(--w) + var(--gap)));\n    font-family: var(--ot-voice); font-style: normal; font-weight: 400; font-size: var(--ot-pp); line-height: 1; letter-spacing: var(--ot-pp-tr);\n    color: transparent;\n    transition: margin-inline var(--ot-moderato) var(--ot-exhale), color var(--ot-allegro);\n  }\n  .ot-toggle[data-state=\"on\"] .ot-toggle-note { color: var(--ot-graphite); transition: margin-inline var(--ot-moderato) var(--ot-exhale), color var(--ot-moderato) var(--ot-exhale) var(--ot-allegro); }\n  /* The arrow's box stands on the baseline and reaches a little over the note's capitals; the text starts under its tip. */\n  .ot-toggle-arrow {\n    display: inline-block; vertical-align: baseline; position: relative; width: var(--len); height: 1.15em; height: calc(1cap + 0.5em); margin-inline-end: calc(var(--len) * -1);\n    color: var(--ot-rule-strong); transition: color var(--ot-allegro);\n  }\n  .ot-toggle[data-state=\"on\"] .ot-toggle-arrow { color: var(--ot-ink); }\n  .ot-toggle-arrow::before, .ot-toggle-arrow::after { content: \"\"; position: absolute; top: 0; box-sizing: border-box; }\n  .ot-toggle-arrow::before { /* the shaft, drawn from its far end toward the word */\n    inset-inline: 0; border-top: var(--ot-hairline) solid currentColor;\n    transform-origin: calc((0.5 + 0.5 * var(--dir)) * 100%) 0; scale: var(--ot-toggle-draw) 1;\n  }\n  .ot-toggle-arrow::after { /* the head: a corner turned to point back, landing as the ink arrives */\n    inset-inline-start: 0; width: 0.36em; height: 0.36em; border-top: var(--ot-hairline) solid currentColor; border-inline-start: var(--ot-hairline) solid currentColor;\n    transform-origin: calc((0.5 - 0.5 * var(--dir)) * 100%) 0; rotate: calc(-45deg * var(--dir));\n    opacity: clamp(0, 3 * var(--ot-toggle-ink) - 2, 1);\n  }\n\n  /* ── guides: after Paul Rand's \"design\", set on its dotted construction grid. Held, the word is set: the two lines\n     it stands between, the baseline and the x-height, are drawn through it in dots and run on past its ends. The\n     italic is scaled until the two x-heights meet, so as the word leans into the italic its letters stay between the\n     same two lines, and the lines show it. Pointing sketches the baseline alone; held, the x-height line draws over\n     it. They pass through: each draws from the start and leaves toward the end. */\n  .ot-toggle[data-variant=\"guides\"] > .ot-toggle-label::before {\n    --c: var(--ot-rule-strong); --run: 0.45em;\n    content: \"\"; grid-area: 1 / 1; align-self: baseline; justify-self: start; pointer-events: none;\n    width: calc(var(--w) + var(--run) * 2); margin-inline: calc(var(--run) * -1); height: calc(1ex + 1px);\n    background: linear-gradient(to right, var(--c) 1px, #0000 0) repeat-x 0 0 / 3px 1px, linear-gradient(to right, var(--c) 1px, #0000 0) repeat-x 0 100% / 3px 1px;\n    mask:\n      linear-gradient(#000 0 0) no-repeat calc((0.5 + (var(--ie) - 0.5) * var(--dir)) * 100%) 0 / calc(var(--ot-toggle-ink) * 100%) 1px,\n      linear-gradient(#000 0 0) no-repeat calc((0.5 + (var(--e) - 0.5) * var(--dir)) * 100%) 100% / calc(var(--ot-toggle-draw) * 100%) 1px;\n    transition: width var(--ot-moderato) var(--ot-exhale);\n  }\n\n  /* Forced colours drop the colours of the marks: say what each one is. */\n  @media (forced-colors: active) {\n    .ot-toggle { color: ButtonText; }\n    .ot-toggle:disabled { color: GrayText; }\n    .ot-toggle:focus-visible, .ot-toggle[data-force~=\"focus\"] { outline-color: Highlight; }\n    .ot-toggle::before, .ot-toggle::after { forced-color-adjust: none; }\n    .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))::before { border-color: GrayText; }\n    .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))[data-state=\"on\"]::before { border-color: ButtonText; }\n    .ot-toggle:is([data-variant=\"fermata\"], :not([data-variant]))::after, .ot-toggle[data-variant=\"tenuto\"]::after { background: ButtonText; }\n    .ot-toggle[data-variant=\"tenuto\"]::before { background-image: linear-gradient(ButtonText 0 0), linear-gradient(GrayText 0 0); }\n    .ot-toggle-note, .ot-toggle[data-variant=\"guides\"] > .ot-toggle-label::before { forced-color-adjust: none; }\n    .ot-toggle[data-state=\"on\"] .ot-toggle-note { color: ButtonText; }\n    .ot-toggle-arrow { color: GrayText; }\n    .ot-toggle[data-state=\"on\"] .ot-toggle-arrow { color: ButtonText; }\n    .ot-toggle[data-variant=\"guides\"] > .ot-toggle-label::before { --c: GrayText; }\n  }\n}\n",
      "type": "registry:file",
      "target": "styles/0nlytype/toggle.css"
    }
  ],
  "css": {
    "@import \"../styles/0nlytype/toggle.css\"": {}
  },
  "meta": {
    "movement": "VI",
    "underneath": "radix",
    "contract": "ot-toggle"
  },
  "type": "registry:ui"
}
