{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"rating","type":"registry:ui","title":"Rating","description":"Stars or thumbs up and down for an AI answer – hover previews, a press sets it and a second press clears it, arrows in one tab stop, read-only with halves (\\\"4.5 out of 5\\\")","dependencies":[],"files":[{"path":"registry/rating/rating.tsx","type":"registry:ui","content":"\"use client\";\n\nimport { useState, type ComponentPropsWithRef, type CSSProperties, type KeyboardEvent as ReactKeyboardEvent } from \"react\";\n\n/*\n * Rating – a single self-contained file.\n * Stars from 1 to 5 (or any max), or thumbs up and down for rating an AI answer. Hovering previews, a press sets it,\n * pressing the chosen one again clears it. It is a radio group: one tab stop, the arrows move and choose. Read-only\n * it shows halves too (\"4.5 out of 5\") and is read out as one picture. A choice fills with a short pop.\n * The styles are injected below, so no extra files are needed.\n */\n\ntype Base = Omit<ComponentPropsWithRef<\"div\">, \"defaultValue\" | \"onChange\" | \"children\"> & {\n  /** Only shows the value – no buttons, read out as one picture (\"4.5 out of 5\"); stars show halves */\n  readOnly?: boolean;\n  disabled?: boolean;\n  /** Stars 16 · 20 · 26 px, thumbs 28 · 32 · 36 px buttons */\n  size?: \"sm\" | \"md\" | \"lg\";\n  /** Pressing the chosen one again (or Delete) clears it */\n  allowClear?: boolean;\n  /** Sends the value with a form (\"\" when nothing is chosen) */\n  name?: string;\n};\n\nexport type StarRatingProps = Base & {\n  variant?: \"stars\";\n  /** 1 to max, or null for none. Read-only it may be a fraction – shown to the nearest half */\n  value?: number | null;\n  defaultValue?: number | null;\n  onValueChange?: (value: number | null) => void;\n  /** How many stars */\n  max?: number;\n  /** How a value is read out – \"3 out of 5\" by default */\n  getValueLabel?: (value: number, max: number) => string;\n};\n\nexport type ThumbsRatingProps = Base & {\n  variant: \"thumbs\";\n  value?: \"up\" | \"down\" | null;\n  defaultValue?: \"up\" | \"down\" | null;\n  onValueChange?: (value: \"up\" | \"down\" | null) => void;\n  /** The two buttons' names – \"Good response\" and \"Bad response\" by default */\n  labels?: { up?: string; down?: string };\n};\n\nexport type RatingProps = StarRatingProps | ThumbsRatingProps;\n\nexport function Rating(props: RatingProps) {\n  return (\n    <>\n      {/* React 19 hoists this into <head> once, no matter how many ratings render */}\n      <style href=\"ui-rating\" precedence=\"default\">\n        {css}\n      </style>\n      {props.variant === \"thumbs\" ? <Thumbs {...props} /> : <Stars {...props} />}\n    </>\n  );\n}\n\n/* ---------- Stars ---------- */\n\nconst num = new Intl.NumberFormat(\"en\", { maximumFractionDigits: 1 });\nconst outOf = (value: number, max: number) => `${num.format(value)} out of ${max}`;\n\nfunction Stars({\n  variant: _variant,\n  value: valueProp,\n  defaultValue = null,\n  onValueChange,\n  max: maxProp = 5,\n  readOnly,\n  disabled,\n  size = \"md\",\n  allowClear = true,\n  getValueLabel = outOf,\n  name,\n  className,\n  ...rest\n}: StarRatingProps) {\n  const [value, setValue] = useControllable(valueProp, defaultValue, onValueChange);\n  const [hover, setHover] = useState<number | null>(null);\n  const [burst, setBurst] = useState({ upTo: 0, n: 0 });\n  const max = Math.min(50, Math.max(1, Math.floor(Number(maxProp) || 5)));\n  const items = Array.from({ length: max }, (_, i) => i + 1);\n  const cls = [\"ui-rtg\", className].filter(Boolean).join(\" \");\n  const sz = size === \"sm\" || size === \"lg\" ? size : \"md\";\n\n  if (readOnly) {\n    const v = typeof value === \"number\" && Number.isFinite(value) ? Math.min(max, Math.max(0, value)) : null;\n    const shown = v == null ? 0 : Math.round(v * 2) / 2;\n    return (\n      <div {...rest} role=\"img\" aria-label={rest[\"aria-label\"] ?? (v == null ? \"No rating\" : getValueLabel(v, max))} className={cls} data-size={sz} data-readonly=\"\">\n        {items.map((i) => (\n          <span key={i} className=\"ui-rtg__star\">\n            <StarGlyph fill={Math.min(1, Math.max(0, shown - (i - 1)))} />\n          </span>\n        ))}\n      </div>\n    );\n  }\n\n  const chosen = typeof value === \"number\" ? Math.min(max, Math.max(1, Math.round(value))) : null;\n  const shown = hover ?? chosen ?? 0;\n  const choose = (i: number | null) => {\n    setValue(i);\n    if (i != null) setBurst((b) => ({ upTo: i, n: b.n + 1 }));\n  };\n\n  const onKeyDown = (e: ReactKeyboardEvent<HTMLButtonElement>) => {\n    if ((e.key === \"Delete\" || e.key === \"Backspace\") && allowClear) {\n      e.preventDefault();\n      choose(null);\n      return;\n    }\n    const back = getComputedStyle(e.currentTarget).direction === \"rtl\";\n    const now = chosen ?? 0;\n    const to =\n      e.key === \"Home\" ? 1 : e.key === \"End\" ? max : e.key === \"ArrowUp\" || e.key === (back ? \"ArrowLeft\" : \"ArrowRight\") ? now + 1 : e.key === \"ArrowDown\" || e.key === (back ? \"ArrowRight\" : \"ArrowLeft\") ? now - 1 : null;\n    if (to == null) return;\n    e.preventDefault();\n    const next = Math.min(max, Math.max(1, to));\n    setHover(null);\n    choose(next);\n    (e.currentTarget.parentElement?.children[next - 1] as HTMLElement | undefined)?.focus();\n  };\n\n  return (\n    <div\n      {...rest}\n      role=\"radiogroup\"\n      aria-label={rest[\"aria-label\"] ?? (rest[\"aria-labelledby\"] ? undefined : \"Rating\")}\n      aria-disabled={disabled || undefined}\n      className={cls}\n      data-size={sz}\n      data-disabled={disabled || undefined}\n      onPointerLeave={(e) => {\n        setHover(null);\n        rest.onPointerLeave?.(e);\n      }}\n    >\n      {items.map((i) => {\n        const pop = burst.n > 0 && i <= burst.upTo && i <= (chosen ?? 0);\n        return (\n          <button\n            key={i}\n            type=\"button\"\n            role=\"radio\"\n            className=\"ui-rtg__star\"\n            aria-checked={chosen === i}\n            aria-label={getValueLabel(i, max)}\n            tabIndex={i === (chosen ?? 1) ? 0 : -1}\n            disabled={disabled}\n            data-hover={hover === i || undefined}\n            onPointerEnter={(e) => {\n              if (e.pointerType === \"mouse\") setHover(i);\n            }}\n            onClick={() => choose(chosen === i && allowClear ? null : i)}\n            onKeyDown={onKeyDown}\n          >\n            <StarGlyph key={pop ? `pop-${burst.n}` : \"rest\"} fill={i <= shown ? 1 : 0} pop={pop} delay={(i - 1) * 40} preview={hover != null} />\n          </button>\n        );\n      })}\n      {name && <input type=\"hidden\" name={name} value={chosen ?? \"\"} />}\n    </div>\n  );\n}\n\n/* Star: Hugeicons Free (MIT, © Hugeicons, hugeicons.com) – drawn solid, a second copy clipped on top for the fill */\nconst STAR =\n  \"M13.7276 3.44418L15.4874 6.99288C15.7274 7.48687 16.3673 7.9607 16.9073 8.05143L20.0969 8.58575C22.1367 8.92853 22.6167 10.4206 21.1468 11.8925L18.6671 14.3927C18.2471 14.8161 18.0172 15.6327 18.1471 16.2175L18.8571 19.3125C19.417 21.7623 18.1271 22.71 15.9774 21.4296L12.9877 19.6452C12.4478 19.3226 11.5579 19.3226 11.0079 19.6452L8.01827 21.4296C5.8785 22.71 4.57865 21.7522 5.13859 19.3125L5.84851 16.2175C5.97849 15.6327 5.74852 14.8161 5.32856 14.3927L2.84884 11.8925C1.389 10.4206 1.85895 8.92853 3.89872 8.58575L7.08837 8.05143C7.61831 7.9607 8.25824 7.48687 8.49821 6.99288L10.258 3.44418C11.2179 1.51861 12.7777 1.51861 13.7276 3.44418Z\";\n\nfunction StarGlyph({ fill, pop, delay = 0, preview }: { fill: number; pop?: boolean; delay?: number; preview?: boolean }) {\n  return (\n    <span\n      className=\"ui-rtg__glyph\"\n      data-pop={pop || undefined}\n      data-preview={preview || undefined}\n      style={{ \"--ui-rtg-f\": fill, animationDelay: `${delay}ms` } as CSSProperties}\n      aria-hidden=\"true\"\n    >\n      <svg viewBox=\"0 0 24 24\" className=\"ui-rtg__empty\" focusable=\"false\">\n        <path d={STAR} fill=\"currentColor\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n      </svg>\n      {fill > 0 && (\n        <svg viewBox=\"0 0 24 24\" className=\"ui-rtg__fill\" focusable=\"false\">\n          <path d={STAR} fill=\"currentColor\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n        </svg>\n      )}\n    </span>\n  );\n}\n\n/* ---------- Thumbs ---------- */\n\nfunction Thumbs({\n  variant: _variant,\n  value: valueProp,\n  defaultValue = null,\n  onValueChange,\n  labels,\n  readOnly,\n  disabled,\n  size = \"md\",\n  allowClear = true,\n  name,\n  className,\n  ...rest\n}: ThumbsRatingProps) {\n  const [value, setValue] = useControllable(valueProp, defaultValue, onValueChange);\n  const [burst, setBurst] = useState(0);\n  const cls = [\"ui-rtg\", \"ui-rtg--thumbs\", className].filter(Boolean).join(\" \");\n  const sz = size === \"sm\" || size === \"lg\" ? size : \"md\";\n  const names = { up: labels?.up ?? \"Good response\", down: labels?.down ?? \"Bad response\" };\n  const chosen = value === \"up\" || value === \"down\" ? value : null;\n  const choose = (v: \"up\" | \"down\" | null) => {\n    setValue(v);\n    if (v) setBurst((n) => n + 1);\n  };\n\n  if (readOnly) {\n    return (\n      <div {...rest} role=\"img\" aria-label={rest[\"aria-label\"] ?? (chosen ? `Rated: ${names[chosen]}` : \"Not rated\")} className={cls} data-size={sz} data-readonly=\"\">\n        {([\"up\", \"down\"] as const).map((k) => (\n          <span key={k} className=\"ui-rtg__thumb\" data-on={chosen === k || undefined}>\n            <ThumbGlyph down={k === \"down\"} solid={chosen === k} />\n          </span>\n        ))}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      {...rest}\n      role=\"radiogroup\"\n      aria-label={rest[\"aria-label\"] ?? (rest[\"aria-labelledby\"] ? undefined : \"Rate this response\")}\n      aria-disabled={disabled || undefined}\n      className={cls}\n      data-size={sz}\n      data-disabled={disabled || undefined}\n    >\n      {([\"up\", \"down\"] as const).map((k) => (\n        <button\n          key={k}\n          type=\"button\"\n          role=\"radio\"\n          className=\"ui-rtg__thumb\"\n          aria-checked={chosen === k}\n          aria-label={names[k]}\n          title={names[k]}\n          tabIndex={k === (chosen ?? \"up\") ? 0 : -1}\n          disabled={disabled}\n          data-on={chosen === k || undefined}\n          onClick={() => choose(chosen === k && allowClear ? null : k)}\n          onKeyDown={(e) => {\n            if ((e.key === \"Delete\" || e.key === \"Backspace\") && allowClear) {\n              e.preventDefault();\n              choose(null);\n              return;\n            }\n            if (![\"ArrowLeft\", \"ArrowRight\", \"ArrowUp\", \"ArrowDown\", \"Home\", \"End\"].includes(e.key)) return;\n            e.preventDefault();\n            const other = e.key === \"Home\" ? \"up\" : e.key === \"End\" ? \"down\" : k === \"up\" ? \"down\" : \"up\";\n            choose(other);\n            (e.currentTarget.parentElement?.children[other === \"up\" ? 0 : 1] as HTMLElement | undefined)?.focus();\n          }}\n        >\n          <ThumbGlyph key={chosen === k ? `pop-${burst}` : \"rest\"} down={k === \"down\"} solid={chosen === k} pop={chosen === k && burst > 0} />\n        </button>\n      ))}\n      {name && <input type=\"hidden\" name={name} value={chosen ?? \"\"} />}\n    </div>\n  );\n}\n\n/* Thumbs up / down: Hugeicons Free (MIT, © Hugeicons, hugeicons.com) – rounded 1.5px strokes, filled when chosen */\nconst THUMB_UP = [\n  \"M2 12.5C2 11.3954 2.89543 10.5 4 10.5C5.65685 10.5 7 11.8431 7 13.5V17.5C7 19.1569 5.65685 20.5 4 20.5C2.89543 20.5 2 19.6046 2 18.5V12.5Z\",\n  \"M15.4787 7.80626L15.2124 8.66634C14.9942 9.37111 14.8851 9.72349 14.969 10.0018C15.0369 10.2269 15.1859 10.421 15.389 10.5487C15.64 10.7065 16.0197 10.7065 16.7791 10.7065H17.1831C19.7532 10.7065 21.0382 10.7065 21.6452 11.4673C21.7145 11.5542 21.7762 11.6467 21.8296 11.7437C22.2965 12.5921 21.7657 13.7351 20.704 16.0211C19.7297 18.1189 19.2425 19.1678 18.338 19.7852C18.2505 19.8449 18.1605 19.9013 18.0683 19.9541C17.116 20.5 15.9362 20.5 13.5764 20.5H13.0646C10.2057 20.5 8.77628 20.5 7.88814 19.6395C7 18.7789 7 17.3939 7 14.6239V13.6503C7 12.1946 7 11.4668 7.25834 10.8006C7.51668 10.1344 8.01135 9.58664 9.00069 8.49112L13.0921 3.96056C13.1947 3.84694 13.246 3.79012 13.2913 3.75075C13.7135 3.38328 14.3652 3.42464 14.7344 3.84235C14.774 3.8871 14.8172 3.94991 14.9036 4.07554C15.0388 4.27205 15.1064 4.37031 15.1654 4.46765C15.6928 5.33913 15.8524 6.37436 15.6108 7.35715C15.5838 7.46692 15.5488 7.5801 15.4787 7.80626Z\",\n];\nconst THUMB_DOWN = [\n  \"M2 11.5C2 12.6046 2.89543 13.5 4 13.5C5.65685 13.5 7 12.1569 7 10.5V6.5C7 4.84315 5.65685 3.5 4 3.5C2.89543 3.5 2 4.39543 2 5.5V11.5Z\",\n  \"M15.4787 16.1937L15.2124 15.3337C14.9942 14.6289 14.8851 14.2765 14.969 13.9982C15.0369 13.7731 15.1859 13.579 15.389 13.4513C15.64 13.2935 16.0197 13.2935 16.7791 13.2935H17.1831C19.7532 13.2935 21.0382 13.2935 21.6452 12.5327C21.7145 12.4458 21.7762 12.3533 21.8296 12.2563C22.2965 11.4079 21.7657 10.2649 20.704 7.9789C19.7297 5.88111 19.2425 4.83222 18.338 4.21485C18.2505 4.15508 18.1605 4.0987 18.0683 4.04586C17.116 3.5 15.9362 3.5 13.5764 3.5H13.0646C10.2057 3.5 8.77628 3.5 7.88814 4.36053C7 5.22106 7 6.60607 7 9.37607V10.3497C7 11.8054 7 12.5332 7.25834 13.1994C7.51668 13.8656 8.01135 14.4134 9.00069 15.5089L13.0921 20.0394C13.1947 20.1531 13.246 20.2099 13.2913 20.2493C13.7135 20.6167 14.3652 20.5754 14.7344 20.1577C14.774 20.1129 14.8172 20.0501 14.9036 19.9245C15.0388 19.728 15.1064 19.6297 15.1654 19.5323C15.6928 18.6609 15.8524 17.6256 15.6108 16.6429C15.5838 16.5331 15.5488 16.4199 15.4787 16.1937Z\",\n];\n\nfunction ThumbGlyph({ down, solid, pop }: { down?: boolean; solid?: boolean; pop?: boolean }) {\n  return (\n    <svg viewBox=\"0 0 24 24\" className=\"ui-rtg__icon\" data-down={down || undefined} data-pop={pop || undefined} focusable=\"false\" aria-hidden=\"true\">\n      {(down ? THUMB_DOWN : THUMB_UP).map((d, i) => (\n        <path key={i} d={d} fill={solid ? \"currentColor\" : \"none\"} stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      ))}\n    </svg>\n  );\n}\n\n/* ---------- Helpers ---------- */\n\nfunction useControllable<T>(value: T | undefined, initial: T, onChange?: (v: T) => void) {\n  const [own, setOwn] = useState(initial);\n  const controlled = value !== undefined;\n  const set = (v: T) => {\n    if (!controlled) setOwn(v);\n    onChange?.(v);\n  };\n  return [controlled ? value : own, set] as const;\n}\n\n/* ---------- Styles ---------- */\n\nconst css = /* css */ `\n/* Colors and motion as variables – override them on .ui-rtg (see Theming in the docs) */\n.ui-rtg {\n  --ui-rtg-star: #f5b000;\n  --ui-rtg-empty: #e4e4e7;\n  --ui-rtg-empty-hover: #d4d4d8;\n  --ui-rtg-icon: var(--aui-muted, #8f8f8f);\n  --ui-rtg-ink: var(--aui-ink, #171717);\n  --ui-rtg-wash: #f4f4f5;\n  --ui-rtg-wash-on: #ececee;\n  --ui-rtg-focus: var(--aui-focus, rgba(0, 96, 226, 0.7));\n  --ui-rtg-ease: var(--aui-ease, cubic-bezier(0.22, 1, 0.36, 1));\n\n  /* A star's size, the space around it (its hit area) and a thumb button's size */\n  --s: 20px;\n  --pad: 3px;\n  --b: 32px;\n  --i: 18px;\n\n  display: inline-flex;\n  align-items: center;\n  gap: 2px;\n  min-width: 0;\n  max-width: 100%;\n  flex-wrap: wrap;\n  vertical-align: middle;\n  -webkit-tap-highlight-color: transparent;\n}\n.ui-rtg[data-size=\"sm\"] { --s: 16px; --pad: 2px; --b: 28px; --i: 16px; gap: 1px; }\n.ui-rtg[data-size=\"lg\"] { --s: 26px; --pad: 3px; --b: 36px; --i: 20px; }\n.ui-rtg[data-readonly] { gap: 2px; }\n.ui-rtg[data-readonly][data-size=\"sm\"] { gap: 1px; }\n.ui-rtg[data-disabled] { opacity: 0.5; }\n\n/* A star: its button is the glyph plus a little room, so the hit area is bigger than the star */\n.ui-rtg__star {\n  display: grid;\n  flex: none;\n  place-items: center;\n  margin: 0;\n  padding: var(--pad);\n  border: 0;\n  border-radius: 8px;\n  background: none;\n  color: inherit;\n  font: inherit;\n  cursor: pointer;\n}\n.ui-rtg[data-readonly] .ui-rtg__star { padding: 0; cursor: default; }\n.ui-rtg__star:disabled { cursor: not-allowed; }\n.ui-rtg__star:focus-visible { outline: 2px solid var(--ui-rtg-focus); outline-offset: 2px; }\n\n.ui-rtg__glyph { position: relative; display: block; width: var(--s); height: var(--s); transition: transform 160ms var(--ui-rtg-ease); }\n.ui-rtg__glyph svg { position: absolute; inset: 0; display: block; width: 100%; height: 100%; overflow: visible; }\n.ui-rtg__empty { color: var(--ui-rtg-empty); transition: color 140ms ease; }\n/* The fill is a second star on top, clipped from the start side – whole, or half for a read-only 4.5 */\n.ui-rtg__fill { color: var(--ui-rtg-star); clip-path: inset(0 calc((1 - var(--ui-rtg-f)) * 100%) 0 0); }\n.ui-rtg:dir(rtl) .ui-rtg__fill { clip-path: inset(0 0 0 calc((1 - var(--ui-rtg-f)) * 100%)); }\n.ui-rtg__star:not(:disabled):hover .ui-rtg__empty { color: var(--ui-rtg-empty-hover); }\n.ui-rtg__star[data-hover] .ui-rtg__glyph { transform: scale(1.12); }\n.ui-rtg__star:not(:disabled):active .ui-rtg__glyph { transform: scale(0.9); }\n/* A choice: the stars up to it pop one after the other */\n.ui-rtg__glyph[data-pop] { animation: ui-rtg-pop 420ms var(--ui-rtg-ease) both; }\n\n/* Thumbs: two icon buttons; the chosen one fills in ink and sits on a gray wash */\n.ui-rtg__thumb {\n  display: grid;\n  flex: none;\n  place-items: center;\n  width: var(--b);\n  height: var(--b);\n  margin: 0;\n  padding: 0;\n  border: 0;\n  border-radius: 9px;\n  background: none;\n  color: var(--ui-rtg-icon);\n  font: inherit;\n  cursor: pointer;\n  transition: background-color 140ms ease, color 140ms ease;\n}\n.ui-rtg[data-readonly] .ui-rtg__thumb { width: auto; height: auto; cursor: default; }\n.ui-rtg[data-readonly] .ui-rtg__thumb:not([data-on]) { opacity: 0.45; }\n.ui-rtg__thumb:not(:disabled):hover { background: var(--ui-rtg-wash); color: var(--ui-rtg-ink); }\n.ui-rtg__thumb[data-on] { color: var(--ui-rtg-ink); }\n.ui-rtg:not([data-readonly]) .ui-rtg__thumb[data-on] { background: var(--ui-rtg-wash-on); }\n.ui-rtg__thumb:disabled { cursor: not-allowed; }\n.ui-rtg__thumb:focus-visible { outline: 2px solid var(--ui-rtg-focus); outline-offset: 2px; }\n.ui-rtg__icon { display: block; width: var(--i); height: var(--i); }\n.ui-rtg__icon[data-pop] { animation: ui-rtg-thumb 460ms var(--ui-rtg-ease); transform-origin: 30% 70%; }\n.ui-rtg__icon[data-pop][data-down] { animation-name: ui-rtg-thumb-down; transform-origin: 30% 30%; }\n\n@keyframes ui-rtg-pop { 0% { transform: scale(0.6); } 55% { transform: scale(1.22); } 100% { transform: scale(1); } }\n@keyframes ui-rtg-thumb { 0% { transform: scale(0.8) rotate(0); } 45% { transform: scale(1.18) rotate(-12deg); } 100% { transform: scale(1) rotate(0); } }\n@keyframes ui-rtg-thumb-down { 0% { transform: scale(0.8) rotate(0); } 45% { transform: scale(1.18) rotate(12deg); } 100% { transform: scale(1) rotate(0); } }\n\n/* Touch screens: a hit area of at least 32px per star and 36px per thumb */\n@media (pointer: coarse) {\n  .ui-rtg { --pad: 6px; --b: 40px; }\n  .ui-rtg[data-size=\"sm\"] { --pad: 8px; --b: 36px; }\n  .ui-rtg[data-size=\"lg\"] { --pad: 5px; --b: 44px; }\n  .ui-rtg:not([data-readonly]) { gap: 0; }\n  .ui-rtg__star[data-hover] .ui-rtg__glyph { transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .ui-rtg__glyph, .ui-rtg__empty, .ui-rtg__thumb { transition: none; }\n  .ui-rtg__glyph[data-pop], .ui-rtg__icon[data-pop] { animation: none; }\n  .ui-rtg__star[data-hover] .ui-rtg__glyph, .ui-rtg__star:active .ui-rtg__glyph { transform: none; }\n}\n\n/* Dark mode: follows a .dark class or data-theme=\"dark\" on any ancestor, e.g. <html> */\n:where(.dark, [data-theme=\"dark\"]) .ui-rtg {\n  --ui-rtg-star: #f0bd1a;\n  --ui-rtg-empty: #2e2e33;\n  --ui-rtg-empty-hover: #3a3a40;\n  --ui-rtg-icon: var(--aui-muted, #8b8b92);\n  --ui-rtg-ink: var(--aui-ink, #ededed);\n  --ui-rtg-wash: #232326;\n  --ui-rtg-wash-on: #2a2a2e;\n  --ui-rtg-focus: var(--aui-focus, rgba(77, 141, 255, 0.8));\n}\n`;\n"}]}