@mediaradar/design-components 0.16.2 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/InfoTip.tsx","../src/AdvertiserQuickFilter.tsx","../src/AdvertiserSearchPrompt.tsx","../src/cn.ts","../src/Badge.tsx","../src/Delta.tsx","../src/CheckBox.tsx","../src/DateRangeFilter.tsx","../src/SearchBar.tsx","../src/SectionRail.tsx","../src/DataScopeFilter.tsx","../src/SelectFilter.tsx","../src/Card.tsx","../src/NoResultsEmptyState.tsx","../src/WorkspaceSelectedCard.tsx","../src/chart-placeholder-shared.tsx","../src/BarChartPlaceholder.tsx","../src/LineChartPlaceholder.tsx","../src/PieChartPlaceholder.tsx","../src/StackedColumnPlaceholder.tsx","../src/Tooltip.tsx","../src/AdvertiserNoResults.tsx","../src/SelectAllVisible.tsx","../src/SelectedSection.tsx","../src/SelectionPicker.tsx","../src/PublisherBreakdownList.tsx","../src/Button.tsx","../src/FilterDropdownFooter.tsx","../src/NameListModal.tsx","../src/ChipTrigger.tsx","../src/FilterChipBar.tsx","../src/SortButton.tsx","../src/tableSort.ts","../src/Pager.tsx","../src/WorkspaceAvatar.tsx","../src/Tag.tsx","../src/TablePagination.tsx","../src/DateRangePicker.tsx","../src/MultiSelectFilter.tsx","../src/Toggle.tsx","../src/AISpark.tsx","../src/Freshness.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Info } from \"lucide-react\";\n\n/**\n * @pattern InfoTip\n * @description Info tooltip — a small info glyph that opens a portalled,\n * viewport-clamped bubble. Mirrors the Publisher Intel header affordance so\n * page subtitles can collapse into the eyebrow.\n * @tokens text-text-tertiary, rounded-control, border-border-default, bg-surface,\n * shadow-overlay, text-text-secondary, focus-visible:outline-border-focus,\n * hover:text-text-primary, tracking-normal\n * @dependencies lucide-react\n * @behavior 'click' mode toggles on click only. 'hover' mode also opens on\n * keyboard focus and closes on blur, so it stays reachable without a mouse —\n * not just a decorative hover effect. Both modes close on Escape and on any\n * outside click. The bubble is portaled to document.body and repositions\n * itself to stay clear of the right viewport edge.\n * @a11y The trigger is a <button> reporting aria-expanded; the bubble is\n * role=\"tooltip\" and Escape dismisses it. It describes its anchor rather\n * than naming it, so the anchor still needs its own accessible name.\n * @usage\n * ```tsx\n * <InfoTip text=\"Trims time periods to data that has finalized across the selected media formats.\" />\n * <InfoTip text=\"Hover variant\" trigger=\"hover\" />\n * ```\n */\nexport interface InfoTipProps {\n /** The bubble's content. */\n text: string;\n /** Glyph size in pixels. */\n size?: number;\n /** Accessible label for the trigger button. */\n label?: string;\n /**\n * 'click' toggles the bubble (default); 'hover' reveals it on hover, and\n * also on keyboard focus so it stays reachable without a pointer.\n */\n trigger?: \"click\" | \"hover\";\n}\n\nexport function InfoTip({ text, size = 11, label = \"More information\", trigger = \"click\" }: InfoTipProps) {\n const [open, setOpen] = useState(false);\n const [pos, setPos] = useState<{ top: number; left: number; width: number } | null>(null);\n const btnRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n if (!btnRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n window.addEventListener(\"mousedown\", onDown);\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"mousedown\", onDown);\n window.removeEventListener(\"keydown\", onKey);\n };\n }, [open]);\n\n // Position the bubble under the glyph, clamped within the viewport so it\n // never squeezes against the right edge.\n const place = () => {\n if (!btnRef.current) return;\n const r = btnRef.current.getBoundingClientRect();\n const width = Math.min(260, window.innerWidth - 24);\n const left = Math.max(12, Math.min(r.left, window.innerWidth - width - 12));\n setPos({ top: r.bottom + 6, left, width });\n };\n\n const show = () => {\n place();\n setOpen(true);\n };\n\n const toggle = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!open) show();\n else setOpen(false);\n };\n\n // Hover trigger also opens on keyboard focus so it stays reachable.\n const hoverProps =\n trigger === \"hover\"\n ? {\n onMouseEnter: show,\n onMouseLeave: () => setOpen(false),\n onFocus: show,\n onBlur: () => setOpen(false),\n }\n : {};\n\n return (\n <>\n <button\n ref={btnRef}\n type=\"button\"\n onClick={toggle}\n aria-label={label}\n aria-expanded={open}\n {...hoverProps}\n className=\"inline-flex cursor-pointer items-center text-text-tertiary transition-colors hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n <Info size={size} aria-hidden=\"true\" />\n </button>\n {open &&\n pos &&\n createPortal(\n <div\n role=\"tooltip\"\n style={{ position: \"fixed\", top: pos.top, left: pos.left, width: pos.width }}\n // z-[90]: deliberately an arbitrary value, not @mediaradar/design-tokens'\n // semantic z-tooltip (1200) -- checked directly: mr-clientapps-insights-\n // studio's real toast layer is a literal z-[100] (ToastProvider.tsx),\n // completely unrelated in scale to design-tokens' 1000+ semantic z-index\n // tokens (z-dropdown/z-modal/z-tooltip). Using the shared token here\n // would render this bubble ABOVE that app's toasts -- the opposite of\n // the original intent (a tooltip should never cover a notification).\n // 90 sits above mr-clientapps' modals (below its own z-[100] toasts) as\n // of this writing -- portals to document.body, becoming a sibling of any\n // open dialog rather than a child of it, so a lower z-index would render\n // invisibly behind the dialog that triggered it. RE-VERIFY this number\n // against any NEW consuming app's own z-index scale before trusting it;\n // this is a leaf component making an assumption about global stacking\n // context it can't fully see.\n className=\"z-[90] rounded-control border border-border-default bg-surface px-3 py-2 text-[12px] font-normal not-italic normal-case leading-relaxed tracking-normal text-text-secondary shadow-overlay\"\n >\n {text}\n </div>,\n document.body\n )}\n </>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Check, ChevronDown, ListChecks, Search, X } from \"lucide-react\";\nimport { AdvertiserSearchPrompt } from \"./AdvertiserSearchPrompt\";\n\n/** Joins truthy class fragments -- a local stand-in so this package doesn't\n * pull in a classnames dependency for one conditional class. */\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/** Above this many visible results, offer a \"select all visible\" shortcut. */\nconst SELECT_ALL_THRESHOLD = 5;\n\n/**\n * @pattern AdvertiserQuickFilter\n * @description Search-first quick filter. Mirrors the standard filter-chip\n * shape (two-line caption + value + chevron) but never preloads the option\n * list -- users must search first, since the advertiser pool is effectively\n * endless. Selections are pinned in a \"Selected (n)\" section at the top so\n * they're never lost when the user runs another search. Named for its\n * original (and still primary) use, but the copy props make it reusable for\n * any dimension that's also search-first in its own filter tray, so the\n * dimension reads the same in the quick bar as it does there.\n * @tokens rounded-control, rounded-card, border-border-default, border-border-strong,\n * border-border-interactive, border-border-focus, bg-surface, bg-input,\n * shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary,\n * text-text-link, bg-brand-primaryAction, text-brand-onprimary,\n * hover:bg-subtle, hover:text-text-primary, placeholder:text-text-tertiary\n * @dependencies lucide-react\n * @behavior The search input auto-focuses the moment the tray opens.\n * Selections buffer in a local draft while open. Without `showFooter`,\n * closing by any means (outside click, Escape, re-click) commits the draft\n * to `onChange`. With `showFooter`, only the Apply button commits -- every\n * other close path discards the draft, so the trigger label never previews\n * an unapplied change. The pinned \"selected\" section persists across\n * searches and collapses when the search is cleared.\n * @a11y Trigger is a <button> with aria-expanded and aria-haspopup; the menu is\n * role=\"dialog\", closed on Escape. Option rows are role=\"checkbox\" with\n * aria-checked, so each row is itself the control -- don't wrap them in\n * another clickable element.\n * @usage\n * ```tsx\n * <AdvertiserQuickFilter options={advertisers} selected={selected} onChange={setSelected} />\n * <AdvertiserQuickFilter options={advertisers} selected={selected} onChange={setSelected} showFooter clearValue={defaults} />\n * ```\n */\nexport interface AdvertiserQuickFilterProps {\n /** Small uppercase label above the value. */\n caption?: string;\n options: { id: string; label: string }[];\n selected: string[];\n onChange: (next: string[]) => void;\n align?: \"left\" | \"right\";\n /** Optional leading icon rendered before the caption/value stack. */\n icon?: React.ReactNode;\n /**\n * Deferred mode: checkbox edits stage in a draft; only the fixed\n * Apply/Clear All footer commits or discards them (no live commit on\n * close). Defaults to false -- live commit-on-close -- so an existing\n * caller's behavior never changes just by picking up a new version of\n * this component.\n */\n showFooter?: boolean;\n /** What \"Clear all\" resets the draft to in footer mode (the page's\n * default selection). */\n clearValue?: string[];\n /** Selected ids the active workspace can't resolve. They stay in the\n * selection -- still committed back, still removable -- but they narrow\n * nothing, so the trigger label leaves them out of the count. */\n parked?: string[];\n /** Search box placeholder. Override alongside the other copy props when\n * the filter isn't advertisers, so the empty and no-results states name\n * the right dimension. */\n searchPlaceholder?: string;\n /** Completes \"Start typing … to filter.\" in the pre-search prompt. */\n promptLabel?: string;\n /** The actionable next step under a no-results message. */\n noResultsHint?: string;\n /** The clear link in footerless mode (unused when `showFooter` is set). */\n clearLabel?: string;\n /**\n * Optional prefix for `data-testid` attributes on the trigger, popover,\n * search input, selected-section toggle, select-all-visible row, each\n * option row (`${testIdPrefix}-option-<slugified-id>`), and the\n * Apply/Clear All footer. Omit entirely for no test-id wiring at all --\n * added specifically so an existing Playwright suite keyed off these ids\n * (mr-clientapps' `AdvertisersPicker`) doesn't lose its locators when\n * swapped over to this shared component.\n */\n testIdPrefix?: string;\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens, trims edge hyphens --\n * matches mr-clientapps' own slug() used to build option test ids. */\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\");\n}\n\nexport function AdvertiserQuickFilter({\n caption = \"Advertiser\",\n options,\n selected,\n onChange,\n align = \"left\",\n icon,\n showFooter = false,\n clearValue = [],\n parked = [],\n searchPlaceholder = \"Search for an advertiser\",\n promptLabel = \"an advertiser name\",\n noResultsHint = \"Try checking your spelling or searching for a broader brand name.\",\n clearLabel = \"Clear advertisers\",\n testIdPrefix,\n}: AdvertiserQuickFilterProps) {\n const [open, setOpen] = useState(false);\n const [q, setQ] = useState(\"\");\n // Draft buffers selections while open; committed to onChange on close (see\n // `showFooter`) so the page isn't re-filtered on every toggle.\n const [draft, setDraft] = useState<string[]>(selected);\n // Selected section starts expanded; clearing the search collapses it so\n // the empty prompt reads cleanly, just like the first open.\n const [selectedOpen, setSelectedOpen] = useState(true);\n const ref = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const clearSearch = () => {\n setQ(\"\");\n setSelectedOpen(false);\n };\n\n // In footer mode, closing (outside click / Escape / re-click) never\n // commits -- only the Apply button does -- so the trigger label never\n // previews the draft. The draft itself is discarded implicitly: the next\n // openTray() re-seeds it from `selected`.\n const close = useCallback(() => {\n setOpen(false);\n setQ(\"\");\n if (showFooter) return;\n if (draft.length !== selected.length || draft.some((id) => !selected.includes(id))) {\n onChange(draft);\n }\n }, [draft, selected, onChange, showFooter]);\n\n const openTray = () => {\n setDraft(selected);\n setSelectedOpen(true);\n setOpen(true);\n };\n\n const apply = () => {\n onChange(draft);\n setOpen(false);\n setQ(\"\");\n };\n\n useEffect(() => {\n if (!open) return;\n inputRef.current?.focus();\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && close();\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n };\n }, [open, close]);\n\n const toggle = (id: string) =>\n setDraft((cur) => (cur.includes(id) ? cur.filter((x) => x !== id) : [...cur, id]));\n\n const ql = q.trim().toLowerCase();\n // Selected rows are pinned and persist regardless of the query.\n const selectedOptions = useMemo(\n () => draft.map((id) => options.find((o) => o.id === id)).filter(Boolean) as { id: string; label: string }[],\n [draft, options]\n );\n // Results exclude what's already selected (those live in the pinned section).\n const results = useMemo(\n () => (ql ? options.filter((o) => !draft.includes(o.id) && o.label.toLowerCase().includes(ql)) : []),\n [ql, options, draft]\n );\n\n const visibleIds = results.map((o) => o.id);\n const allVisibleSelected = visibleIds.length > 0 && visibleIds.every((id) => draft.includes(id));\n const toggleAllVisible = () =>\n setDraft((cur) =>\n allVisibleSelected ? cur.filter((id) => !visibleIds.includes(id)) : [...new Set([...cur, ...visibleIds])]\n );\n\n const shown = open && !showFooter ? draft : selected;\n // Parked ids are held, not applied, so the label counts only what's narrowing.\n const counted = parked.length ? shown.filter((id) => !parked.includes(id)) : shown;\n const value =\n counted.length === 0\n ? \"All\"\n : counted.length === 1\n ? options.find((o) => o.id === counted[0])?.label ?? \"1 selected\"\n : `${counted.length} selected`;\n\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-trigger`}\n onClick={() => (open ? close() : openTray())}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n className=\"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n {icon && <span className=\"shrink-0 text-text-tertiary\">{icon}</span>}\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">{caption}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div\n className={cx(\n \"absolute top-[calc(100%+8px)] z-30 flex w-72 flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay\",\n align === \"right\" ? \"right-0\" : \"left-0\"\n )}\n role=\"dialog\"\n aria-label={caption}\n data-testid={testIdPrefix && `${testIdPrefix}-popover`}\n >\n <div className=\"border-b border-border-default p-2\">\n <div className=\"flex h-9 items-center gap-2 rounded-control border border-border-default bg-input px-2.5 focus-within:border-border-focus focus-within:ring-2 focus-within:ring-border-focus/30\">\n <Search size={14} className=\"shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onMouseDown={() => setSelectedOpen(false)}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n data-testid={testIdPrefix && `${testIdPrefix}-search`}\n className=\"h-full min-w-0 flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary\"\n />\n {q && (\n <button\n type=\"button\"\n onClick={clearSearch}\n aria-label=\"Clear search\"\n className=\"shrink-0 text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <X size={13} />\n </button>\n )}\n </div>\n </div>\n\n <div className=\"max-h-[300px] overflow-y-auto p-1\">\n {/* Pinned selected -- persists across searches so it's never lost. */}\n {selectedOptions.length > 0 && (\n <div className=\"mb-1 border-b border-border-default pb-1\">\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-selected-toggle`}\n onClick={() => setSelectedOpen((v) => !v)}\n aria-expanded={selectedOpen}\n className=\"flex w-full items-center gap-1.5 rounded-control px-2 py-1 text-left text-[11px] font-semibold uppercase tracking-wide text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <ChevronDown\n size={13}\n aria-hidden=\"true\"\n className={cx(\"transition-transform\", !selectedOpen && \"-rotate-90\")}\n />\n Selected ({selectedOptions.length})\n </button>\n {selectedOpen && (\n <div className=\"flex flex-col gap-0.5\">\n {selectedOptions.map((o) => (\n <OptionRow\n key={o.id}\n label={o.label}\n checked\n onToggle={() => toggle(o.id)}\n testId={testIdPrefix && `${testIdPrefix}-option-${slug(o.id)}`}\n />\n ))}\n </div>\n )}\n </div>\n )}\n\n {!ql ? (\n <AdvertiserSearchPrompt label={promptLabel} />\n ) : results.length === 0 ? (\n <div className=\"flex flex-col items-center gap-1.5 px-4 py-8 text-center\">\n <p className=\"text-[13px] font-medium text-text-primary\">No results found for &ldquo;{q.trim()}&rdquo;</p>\n <p className=\"text-[12px] leading-snug text-text-tertiary\">{noResultsHint}</p>\n </div>\n ) : (\n <>\n {results.length > SELECT_ALL_THRESHOLD && (\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-select-all-visible`}\n onClick={toggleAllVisible}\n className=\"flex w-full items-center gap-2 rounded-control px-2 py-1.5 text-left text-[12px] font-semibold text-text-link transition-colors hover:bg-subtle\"\n >\n <ListChecks size={14} aria-hidden=\"true\" />\n {allVisibleSelected ? `Deselect ${results.length} visible` : `Select all ${results.length} visible`}\n </button>\n )}\n {results.map((o) => (\n <OptionRow\n key={o.id}\n label={o.label}\n checked={false}\n onToggle={() => toggle(o.id)}\n testId={testIdPrefix && `${testIdPrefix}-option-${slug(o.id)}`}\n />\n ))}\n </>\n )}\n </div>\n\n {showFooter ? (\n <div className=\"flex items-center justify-between border-t border-border-default px-3 py-2.5\">\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-clear-all`}\n onClick={() => setDraft(clearValue)}\n disabled={draft.length === 0}\n className=\"text-[13px] font-medium text-text-secondary transition-colors hover:text-text-primary disabled:opacity-40\"\n >\n Clear all\n </button>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-apply`}\n onClick={apply}\n className=\"rounded-control bg-brand-primaryAction px-5 py-2 text-[13px] font-semibold text-brand-onprimary transition hover:brightness-110\"\n >\n Apply\n </button>\n </div>\n ) : (\n draft.length > 0 && (\n <div className=\"flex items-center justify-between border-t border-border-default p-2\">\n <span className=\"text-[11px] text-text-tertiary\">{draft.length} selected</span>\n <button\n type=\"button\"\n onClick={() => setDraft([])}\n className=\"text-[12px] font-medium text-text-link hover:underline\"\n >\n {clearLabel}\n </button>\n </div>\n )\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction OptionRow({\n label,\n checked,\n onToggle,\n testId,\n}: {\n label: string;\n checked: boolean;\n onToggle: () => void;\n testId?: string;\n}) {\n return (\n <div\n onClick={onToggle}\n className=\"flex cursor-pointer items-center gap-2.5 rounded-control px-2 py-2 transition-colors hover:bg-subtle\"\n >\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={checked}\n aria-label={label}\n data-testid={testId}\n onClick={(e) => {\n e.stopPropagation();\n onToggle();\n }}\n className={cx(\n \"flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors\",\n \"focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n checked\n ? \"border-transparent bg-brand-primaryAction text-brand-onprimary\"\n : \"border-border-interactive bg-surface hover:border-brand-primaryAction\"\n )}\n >\n {checked && <Check size={13} strokeWidth={3} />}\n </button>\n <span className=\"flex-1 text-[14px] text-text-primary\">{label}</span>\n </div>\n );\n}\n","import { Search } from \"lucide-react\";\n\n/**\n * @pattern AdvertiserSearchPrompt\n * @description Pre-search empty state for a search-first picker — shown the\n * moment the tray opens, before anything has been typed. Used for option\n * pools too large to preload (the advertiser list is effectively endless),\n * where the caller must search before any options can be listed at all.\n * Named for its original (and still primary) use, but the `label` prop makes\n * it reusable for any other search-first dimension (a league picker, say).\n * @tokens bg-subtle, text-text-tertiary\n * @dependencies lucide-react\n * @usage\n * ```tsx\n * <AdvertiserSearchPrompt />\n * <AdvertiserSearchPrompt label=\"a league name\" />\n * ```\n */\nexport interface AdvertiserSearchPromptProps {\n /** Completes \"Start typing … to filter.\" */\n label?: string;\n}\n\nexport function AdvertiserSearchPrompt({ label = \"an advertiser name\" }: AdvertiserSearchPromptProps) {\n return (\n <div className=\"flex flex-col items-center gap-2 px-4 py-8 text-center\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-subtle text-text-tertiary\">\n <Search size={16} aria-hidden=\"true\" />\n </span>\n <p className=\"text-[12px] leading-snug text-text-tertiary\">Start typing {label} to filter.</p>\n </div>\n );\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\n/**\n * tailwind-merge, taught about this design system's own font-size steps.\n *\n * Without this, `text-micro` and `text-dense` are silently DELETED. Both look\n * like text-colour classes to tailwind-merge -- it has no way to know `micro`\n * is a size and `secondary` is a colour -- so a component doing\n * `cn(\"text-micro\", \"text-text-secondary\")` ends up with only the colour, and\n * the badge renders at the inherited 16px instead of 10px.\n *\n * It fails silently and only in components that set a size AND a colour\n * through cn(), which is most of them. Found by measuring a rendered badge,\n * not by any build error: the class is present in the source, present in the\n * bundle, and simply absent from the DOM.\n *\n * Any future custom font-size token has to be added here too.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n \"font-size\": [{ text: [\"micro\", \"dense\"] }],\n },\n },\n});\n\n// The tailwind-merge step is what lets a caller's className override a\n// component's own class for the same property (e.g. <Button className=\"px-2\">);\n// a plain join would keep both.\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"./cn\";\n\n/**\n * Fill and ink. `tone` answers \"what kind of thing is this\", never \"what\n * colour do I want\" -- a caller reaching for `danger` because red looks good\n * is the start of the drift this component replaces.\n */\nexport type BadgeTone =\n | \"neutral\"\n | \"brand\"\n | \"brandSolid\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"ai\"\n | \"overlay\";\n\n/**\n * Shape and case. Orthogonal to tone: any tone can be any kind, which is what\n * keeps this two small props instead of one list of every combination the\n * product happens to use today.\n */\nexport type BadgeKind = \"label\" | \"count\" | \"eyebrow\";\n\nconst TONE: Record<BadgeTone, string> = {\n neutral: \"bg-subtle text-text-secondary\",\n brand: \"bg-brand-primarySoft text-brand-primaryAction\",\n // Solid, not a tint. A filter count's whole job is to be noticed -- it is\n // what tells you the view you are looking at is filtered at all -- so it\n // carries the full brand fill rather than the soft wash `brand` uses for a\n // label like \"Primary\". Missed in the first pass, which collapsed both into\n // one tone; the swap onto real call sites is what surfaced it.\n brandSolid: \"bg-brand-primaryAction text-brand-onprimary\",\n success: \"bg-status-success/15 text-text-success\",\n // Heavier tint than success and danger on purpose. Equal opacity does not\n // give equal presence: the warning amber (#b8843a) sits far closer to the\n // warm canvas than red or green do, so the same 15% that reads clearly for\n // those two disappeared here and the badge looked neutral.\n warning: \"bg-status-warning/30 text-text-warning\",\n danger: \"bg-status-danger/15 text-text-danger\",\n // The gradient is the OUTLINE, not the fill. As a fill it was the most\n // distinct tone by a mile, but white text on it ran from 7.5:1 at the blue\n // end down to 2.1:1 at the amber end -- the last third of every AI badge\n // was unreadable. Outlining keeps the gradient as the signal and puts the\n // text back on a flat tint.\n //\n // Two backgrounds in one box: the tint clipped to the padding box, the\n // gradient to the border box, over a transparent 1px border. The tint is\n // opaque on purpose -- an outline over a transparent centre would let the\n // gradient show through the middle, and the badge has to sit on both the\n // canvas and a card without knowing which.\n ai: \"border border-transparent text-ai-ontint\",\n // Sits on artwork, not on the canvas, so it carries its own scrim rather\n // than a theme surface -- the image behind it is not a colour we control.\n overlay: \"bg-scrim text-brand-onprimary\",\n};\n\n// The gradient outline needs two stacked backgrounds -- the tint clipped to\n// the padding box, the gradient to the border box -- which is a poor fit for\n// a utility class: as an arbitrary value it is an unreadable single token, and\n// its commas collide with the comma-separated @tokens contract the drift check\n// reads. A style object says the same thing legibly and keeps every class in\n// TONE a real, checkable one.\nconst TONE_STYLE: Partial<Record<BadgeTone, CSSProperties>> = {\n ai: {\n background:\n \"linear-gradient(var(--mr-color-ai-tint), var(--mr-color-ai-tint)) padding-box, \" +\n \"var(--mr-color-ai-gradient) border-box\",\n },\n};\n\nconst KIND: Record<BadgeKind, string> = {\n // Twice the vertical room the first version had. At py-0.5 the pill hugged\n // its text and read as a tight little tag; at py-1 it reads as a deliberate\n // object. Taken from the status pills the product had already arrived at by\n // hand, which were noticeably more comfortable than anything else -- the\n // breathing room was what made them so, not their extra pixel of type.\n label: \"px-2.5 py-1\",\n // Square-ish and centred, with a floor width so a 1-digit and a 3-digit\n // count are the same shape, and lining figures so the width does not shift\n // as the number changes.\n count: \"h-[18px] min-w-[18px] justify-center px-1.5 tabular-nums\",\n // The only kind that shouts. Caps need the letterspacing -- caps set tight\n // are harder to read than the sentence case they replaced.\n eyebrow: \"px-2.5 py-1 uppercase tracking-wider\",\n};\n\ninterface BadgeProps {\n /** What kind of thing this marks. Not a colour choice. */\n tone?: BadgeTone;\n /** Shape and case. `count` for a number, `eyebrow` for a category label. */\n kind?: BadgeKind;\n /**\n * Draws a small filled dot before the label, in the tone's own ink. For a\n * status that is scanned down a column rather than read -- the dot is what\n * the eye follows, and it carries the colour at a size the text cannot.\n * Purely decorative: the label is the accessible content, so the dot is\n * hidden from assistive tech rather than announced as a second thing.\n */\n dot?: boolean;\n /** Text, or an icon plus text. Keep it to a few words -- a badge annotates, it does not explain. */\n children: ReactNode;\n className?: string;\n}\n\n/**\n * @pattern Badge\n * @description The one small label that annotates something else: a count on\n * a filter, a status, a category, an AI marker, a flag over artwork. Two\n * props -- `tone` (what kind of thing) and `kind` (shape and case) -- which\n * between them cover every badge treatment in the product.\n * @props\n * tone?: 'neutral' | 'brand' | 'brandSolid' | 'success' | 'warning' | 'danger' | 'ai' | 'overlay' (default 'neutral')\n * kind?: 'label' | 'count' | 'eyebrow' (default 'label')\n * dot?: boolean (default false) -- a filled dot before the label, in the tone's ink\n * children: ReactNode\n * @tokens text-micro, rounded-full, bg-current, bg-subtle, bg-brand-primarySoft, bg-brand-primaryAction,\n * bg-status-success/15, bg-status-warning/30, bg-status-danger/15, bg-scrim,\n * text-text-secondary, text-brand-primaryAction, text-text-success,\n * text-text-warning, text-text-danger, text-ai-ontint, text-brand-onprimary,\n * border-transparent\n * @behavior Not interactive and carries no role: a badge is a label on\n * something else, so it is read as part of that thing rather than announced\n * separately. Anything clickable is a Button or a filter chip, not a Badge.\n * Every badge is one size -- the `micro` step (11px) -- because a badge\n * that competes with the content it annotates has stopped being a badge.\n * @variant neutral - Default. A category, a count of something unremarkable, a quiet flag.\n * @variant brand - This item is special in a way the product cares about -- primary, selected, yours.\n * @variant brandSolid - Full brand fill, for a count that has to be noticed: active filters, unread, selected.\n * @variant success - A finished or healthy state. Never just \"green because it is good news\".\n * @variant warning - Needs attention but is not broken. Partial data, an approaching limit.\n * @variant danger - Failed, expired, or over a hard limit. Not merely \"important\".\n * @variant ai - Generated or AI-assisted content, so the reader knows where it came from.\n * @variant overlay - Sits on top of an image or video still, where no theme surface exists behind it.\n * @use when you need to annotate something else -- a status on a row, a count\n * on a filter tab, a category on a card, a flag over a thumbnail.\n * @use when the label is a few words at most and the reader does not need to\n * act on it.\n * @avoid when the thing is clickable -- use Button, or a filter chip. A badge\n * has no role, no focus state and no hit target, so making one clickable\n * hides the action from keyboard and screen-reader users entirely.\n * @avoid when the text is a sentence, or needs to wrap. A badge that wraps\n * has become a callout; use one.\n * @avoid when you are choosing the tone by colour rather than by meaning. A\n * red badge that does not mean failure teaches readers to ignore red.\n * @avoid when several sit in a row and all say something different -- that is\n * a definition list wearing badges, and reads as noise.\n * @usage\n * ```tsx\n * <Badge>Financial Services</Badge>\n * <Badge tone=\"brandSolid\" kind=\"count\">{activeFilters}</Badge>\n * <Badge tone=\"warning\">Partial month</Badge>\n * <Badge tone=\"success\" dot>Completed</Badge>\n * <Badge kind=\"eyebrow\" tone=\"neutral\">Saved view</Badge>\n * <Badge tone=\"brand\"><Check size={11} aria-hidden=\"true\" />Primary</Badge>\n * ```\n */\nexport function Badge({ tone = \"neutral\", kind = \"label\", dot = false, children, className }: BadgeProps) {\n return (\n <span\n style={TONE_STYLE[tone]}\n className={cn(\n // `inline-flex` + `gap` so a leading icon sits on the text baseline\n // without every caller re-inventing the spacing. `shrink-0` because a\n // badge is almost always beside flexible text that would otherwise\n // squash it. `whitespace-nowrap` because a wrapped badge is a bug.\n \"inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full text-micro font-semibold leading-none\",\n TONE[tone],\n KIND[kind],\n className\n )}\n >\n {dot && <span aria-hidden=\"true\" className=\"size-1.5 shrink-0 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\nexport type { BadgeProps };\n","import { ArrowDownRight, ArrowUpRight } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\ninterface DeltaProps {\n /** The change itself. Its sign picks the direction; render the absolute value. */\n value: number;\n /** What the number is in -- \"%\" for a percentage, \"pts\" for share points. */\n suffix?: string;\n /**\n * Adds a direction arrow before the number. For a column of deltas scanned\n * rather than read, where the arrow is what the eye follows. A single delta\n * beside a figure does not need one -- the sign already says which way.\n */\n arrow?: boolean;\n /** Appended after the suffix, e.g. \"YoY\". Keep it to one or two words. */\n period?: string;\n className?: string;\n}\n\n/**\n * @pattern Delta\n * @description A change over time -- the +6.2% / -2.1% beside a figure. Green\n * up, red down, always with an explicit sign.\n * @props\n * value: number -- sign picks the direction\n * suffix?: string -- \"%\" or \"pts\"\n * arrow?: boolean (default false) -- direction arrow, for a column scanned rather than read\n * period?: string -- e.g. \"YoY\"\n * @tokens text-text-success, text-text-danger\n * @dependencies lucide-react\n * @behavior Takes the type size of whatever contains it rather than setting\n * its own, because it is inline text inside a table cell or a card rather\n * than a box of its own -- a fixed size would fight the density its table\n * already chose.\n * @a11y The sign is the point: colour alone cannot carry direction, for\n * anyone who cannot distinguish the two and for anyone reading it printed or\n * in greyscale. `+` and `-` are always rendered, so the colour is\n * reinforcement rather than the only signal. The arrow is decorative and\n * hidden, since the sign beside it already says the same thing.\n * @use when showing a change against a previous period beside the figure it\n * relates to.\n * @use with `arrow` when deltas run down a column and the reader is scanning\n * for the ones that moved.\n * @avoid when the number is not a change -- a share, a total or a rate is\n * just a number, and colouring it green or red tells the reader something\n * untrue about it.\n * @avoid when up is not good. Green-for-up reads as green-for-better, so a\n * rising cost or a rising error rate needs its own treatment rather than this\n * one inverted, which nobody will notice.\n * @usage\n * ```tsx\n * <Delta value={6.2} suffix=\"%\" />\n * <Delta value={-2.1} suffix=\"%\" period=\"YoY\" />\n * <Delta value={1.4} suffix=\"pts\" arrow />\n * ```\n */\nexport function Delta({ value, suffix = \"%\", arrow = false, period, className }: DeltaProps) {\n const up = value >= 0;\n return (\n <span\n className={cn(\n \"inline-flex items-center gap-0.5 font-medium tabular-nums\",\n up ? \"text-text-success\" : \"text-text-danger\",\n className\n )}\n >\n {arrow &&\n (up ? (\n <ArrowUpRight size={13} aria-hidden=\"true\" />\n ) : (\n <ArrowDownRight size={13} aria-hidden=\"true\" />\n ))}\n {/* A true minus sign, not a hyphen: it matches the plus in width and\n sits on the same optical centre, so a column of deltas stays aligned. */}\n {up ? \"+\" : \"−\"}\n {Math.abs(value).toFixed(1)}\n {suffix}\n {period && <span className=\"ml-0.5\">{period}</span>}\n </span>\n );\n}\n\nexport type { DeltaProps };\n","\"use client\";\n\nimport { Check, Minus } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\n/** Shared box geometry and fill. `CheckBox` and `CheckBoxBox` must never drift\n * apart, so both render through this. */\nfunction boxClass(on: boolean, disabled?: boolean) {\n return cn(\n \"flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors\",\n on ? \"border-transparent bg-brand-primaryAction text-white\" : \"border-border-interactive bg-input\",\n disabled && \"cursor-not-allowed opacity-50\"\n );\n}\n\n/** The check / dash glyph. Nothing is drawn in the unchecked state. */\nfunction Glyph({ checked, indeterminate }: { checked: boolean; indeterminate?: boolean }) {\n if (indeterminate) return <Minus size={13} strokeWidth={3} />;\n return checked ? <Check size={13} strokeWidth={3} /> : null;\n}\n\n/**\n * @pattern CheckBox\n * @description Tri-state checkbox rendered as a `<button>` (not a native\n * `<input type=\"checkbox\">`), so it can carry an indeterminate \"some but not\n * all\" state without the native element's limited styling hooks. Designed to\n * be dropped into a row that already has its own click-to-toggle handler\n * (a common list/table pattern) without double-firing. Where the row itself\n * is the control, use `CheckBoxBox` instead.\n * @tokens bg-brand-primaryAction, border-border-interactive, bg-input,\n * hover:border-brand-primaryAction, focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior `aria-checked` is `\"mixed\"` when indeterminate, otherwise the\n * plain boolean. Indeterminate renders a dash (Minus) instead of a\n * checkmark; checked renders a checkmark; neither renders nothing. The\n * unchecked state previews the brand action color on hover, matching the\n * color the box fills with once checked -- the hover state is a preview of\n * the click's effect, not an unrelated highlight. `onClick` calls\n * `stopPropagation` before firing `onChange` by default, so nesting this\n * inside a row that toggles on its own click can't fire the toggle twice;\n * pass `stopPropagation={false}` where the row should also see the click.\n * @a11y The <button> itself carries role=\"checkbox\" and aria-checked (\"mixed\"\n * when indeterminate), so it IS the control -- never nest it inside\n * another button or a row that is itself clickable. `ariaLabel` is\n * required because the box renders no text. Where the whole row should be\n * the control, use CheckBoxBox inside your own <button role=\"checkbox\">\n * instead: a <button> inside a <button> is invalid markup, and a <div\n * onClick> wrapper is not keyboard-reachable at all.\n * @usage\n * ```tsx\n * <CheckBox checked={selected} ariaLabel=\"Select row\" onChange={toggle} />\n * <CheckBox checked={allSelected} indeterminate={someSelected} ariaLabel=\"Select all\" onChange={toggleAll} />\n * <CheckBox checked={false} disabled ariaLabel=\"Select row\" title=\"Max 5 rows -- remove one first\" onChange={toggle} />\n * ```\n */\nexport interface CheckBoxProps {\n /** Whether the box is checked. Controlled: the parent owns this value. */\n checked: boolean;\n /**\n * Some-but-not-all state for a \"select all\" checkbox -- shows a dash\n * instead of a check, and reports `aria-checked=\"mixed\"` instead of the\n * plain boolean.\n */\n indeterminate?: boolean;\n /**\n * Called on click with no argument -- flip `checked` yourself. By default\n * the click doesn't bubble, so a row that toggles on its own click won't\n * fire twice.\n */\n onChange: () => void;\n /** Accessible label -- required since the control carries no visible text of its own. */\n ariaLabel: string;\n /** Blocks clicks, dims the box to 50% opacity, and cancels its hover preview. */\n disabled?: boolean;\n /**\n * Whether the click stops bubbling to an ancestor. Defaults to `true`,\n * which is what a row that toggles on its own click needs. Set `false`\n * when the ancestor should also see the click -- e.g. a row that both\n * selects and opens a detail panel.\n */\n stopPropagation?: boolean;\n /** Forwarded as `data-testid`, for Playwright/test selectors. */\n testId?: string;\n /**\n * Native tooltip -- e.g. explaining why a disabled box is disabled. Forwarded\n * directly to the underlying `<button>`, same as a plain HTML `title` would\n * be on any other disabled control.\n */\n title?: string;\n /** Extra classes merged onto the box -- e.g. a cursor or margin override. */\n className?: string;\n}\n\nexport function CheckBox({\n checked,\n indeterminate,\n onChange,\n ariaLabel,\n disabled,\n stopPropagation = true,\n testId,\n title,\n className,\n}: CheckBoxProps) {\n const on = checked || !!indeterminate;\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={indeterminate ? \"mixed\" : checked}\n aria-label={ariaLabel}\n title={title}\n disabled={disabled}\n data-testid={testId}\n onClick={(e) => {\n // Stops the click from bubbling to a row wrapper that toggles on its\n // own click -- without this, a checkbox nested in such a row fires\n // its own onChange AND the row's, double-toggling back to a no-op.\n if (stopPropagation) e.stopPropagation();\n onChange();\n }}\n className={cn(\n boxClass(on, disabled),\n \"focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n !on && \"hover:border-brand-primaryAction\",\n // Cancels the unchecked hover-border preview when disabled -- without\n // this, a disabled box still visually previews the \"you can click\n // this\" affordance on hover even though the click does nothing.\n disabled && \"hover:border-border-interactive\",\n className\n )}\n >\n <Glyph checked={checked} indeterminate={indeterminate} />\n </button>\n );\n}\n\n/**\n * @pattern CheckBoxBox\n * @description Presentational checkbox -- draws the same box as `CheckBox`\n * and nothing else. Use it when an ancestor already carries the interaction\n * and the checkbox semantics (a clickable option row, a `<label>`), since a\n * `<button>` inside a `<button>` is invalid markup and a second focus stop on\n * the same control is worse for keyboard users, not better. The owning\n * element supplies `role=\"checkbox\"` and `aria-checked`; this is\n * `aria-hidden` so the state isn't announced twice.\n * @tokens bg-brand-primaryAction, border-border-interactive, bg-input\n * @dependencies lucide-react\n * @behavior Renders through the same `boxClass` as `CheckBox`, so geometry\n * and fill can't drift. Takes neither the focus ring nor the hover border,\n * because the row around it owns both. Without this, a row that is itself\n * the control has no correct option: nesting the interactive `CheckBox`\n * produces a button inside a button, and dropping to a `<div>` with a click\n * handler loses keyboard access entirely.\n * @a11y Presentational only: aria-hidden, no focus stop, no click handling. The\n * ancestor owns role=\"checkbox\", aria-checked, the accessible name and the\n * click. Use it exactly when that ancestor is itself the control; use\n * CheckBox when the box is the control.\n * @usage\n * ```tsx\n * <button type=\"button\" role=\"checkbox\" aria-checked={on} onClick={toggle}>\n * <CheckBoxBox checked={on} />\n * <span>Cable TV</span>\n * </button>\n * ```\n */\nexport interface CheckBoxBoxProps {\n /** Whether the box is checked. The owning element reports this to AT. */\n checked: boolean;\n /** Some-but-not-all state -- shows a dash instead of a check. */\n indeterminate?: boolean;\n /** Dims the box to 50% opacity, matching `CheckBox`'s disabled treatment. */\n disabled?: boolean;\n /** Extra classes merged onto the box. */\n className?: string;\n}\n\nexport function CheckBoxBox({ checked, indeterminate, disabled, className }: CheckBoxBoxProps) {\n return (\n <span aria-hidden=\"true\" className={cn(boxClass(checked || !!indeterminate, disabled), className)}>\n <Glyph checked={checked} indeterminate={indeterminate} />\n </span>\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { ChevronDown, ChevronLeft, ChevronRight } from \"lucide-react\";\n\nconst DEFAULT_SHORTCUTS = [\n \"Year to date\",\n \"Rolling 3 months\",\n \"Rolling 6 months\",\n \"Rolling 12 months\",\n \"Previous quarter\",\n \"Current quarter to date\",\n \"Previous month\",\n \"Current month\",\n \"Custom\",\n] as const;\n\n// Creative Intel's own preset list -- day-level shortcuts (Today/Yesterday/Last\n// N days) plus a longer history option, distinct from the quarter-oriented set\n// the other dashboards use. Content and order confirmed identical to\n// mr-clientapps-insights-studio's own hardcoded PRESETS list (its\n// DateRangeCalendar.tsx) -- this is that same list, made representable via a\n// prop instead of forked into a second hardcoded copy.\nconst CREATIVE_INTEL_SHORTCUTS = [\n \"Today\",\n \"Yesterday\",\n \"Last 7 days\",\n \"Last 14 days\",\n \"Last month\",\n \"Rolling 3 months\",\n \"Rolling 6 months\",\n \"Rolling 12 months\",\n \"Year to date\",\n \"Previous year\",\n \"All available history\",\n \"Custom\",\n] as const;\n\ntype Shortcut = (typeof DEFAULT_SHORTCUTS)[number] | (typeof CREATIVE_INTEL_SHORTCUTS)[number];\n\nconst WEEKDAYS = [\"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\", \"Su\"];\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n];\n\n// ── date helpers ─────────────────────────────────────────────────────────────\nconst startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate());\nconst addDays = (d: Date, n: number) => {\n const x = new Date(d);\n x.setDate(x.getDate() + n);\n return x;\n};\nconst addMonths = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth() + n, 1);\nconst sameDay = (a: Date, b: Date) =>\n a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\nconst fmt = (d: Date) => `${MONTHS[d.getMonth()].slice(0, 3)} ${d.getDate()}, ${d.getFullYear()}`;\n/** Full resolved range, e.g. \"December 16, 2025 - June 16, 2026\". */\nconst fmtFull = (d: Date) => `${MONTHS[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;\nconst fullRangeLabel = (s: Date, e: Date) => `${fmtFull(s)} - ${fmtFull(e)}`;\nconst presetLabel = (sc: Shortcut) => (sc === \"Custom\" ? \"Custom range\" : sc);\n\nfunction presetRange(key: Shortcut, today: Date): [Date, Date] | null {\n const t = startOfDay(today);\n const qMonth = Math.floor(t.getMonth() / 3) * 3;\n switch (key) {\n case \"Year to date\": return [new Date(t.getFullYear(), 0, 1), t];\n case \"Rolling 3 months\": return [addMonths(t, -3), t];\n case \"Rolling 6 months\": return [addMonths(t, -6), t];\n case \"Rolling 12 months\": return [addMonths(t, -12), t];\n case \"Previous quarter\": {\n const s = new Date(t.getFullYear(), qMonth - 3, 1);\n const e = new Date(t.getFullYear(), qMonth, 0);\n return [s, e];\n }\n case \"Current quarter to date\": return [new Date(t.getFullYear(), qMonth, 1), t];\n case \"Previous month\": {\n const s = new Date(t.getFullYear(), t.getMonth() - 1, 1);\n const e = new Date(t.getFullYear(), t.getMonth(), 0);\n return [s, e];\n }\n case \"Current month\": return [new Date(t.getFullYear(), t.getMonth(), 1), t];\n case \"Today\": return [t, t];\n case \"Yesterday\": { const y = addDays(t, -1); return [y, y]; }\n case \"Last 7 days\": return [addDays(t, -6), t];\n case \"Last 14 days\": return [addDays(t, -13), t];\n case \"Last month\": {\n const s = new Date(t.getFullYear(), t.getMonth() - 1, 1);\n const e = new Date(t.getFullYear(), t.getMonth(), 0);\n return [s, e];\n }\n case \"Previous year\": return [new Date(t.getFullYear() - 1, 0, 1), new Date(t.getFullYear() - 1, 11, 31)];\n case \"All available history\": return [new Date(2000, 0, 1), t];\n default: return null; // Custom\n }\n}\n\n/** 42-cell (6-week) Monday-first grid for a given month. */\nfunction monthGrid(year: number, month: number): Date[] {\n const first = new Date(year, month, 1);\n const dow = (first.getDay() + 6) % 7; // Mon = 0\n const gridStart = addDays(first, -dow);\n return Array.from({ length: 42 }, (_, i) => addDays(gridStart, i));\n}\n\nfunction matchShortcut(shortcuts: readonly Shortcut[], label?: string): Shortcut {\n if (!label) return \"Rolling 12 months\";\n const hit = shortcuts.find((s) => s.toLowerCase() === label.toLowerCase());\n return hit || \"Custom\";\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens -- used for each preset\n * option's data-testid. NOTE: this does not match mr-clientapps' own\n * CreativeDatePreset enum keys 1:1 (e.g. \"Last 7 days\" -> \"last-7-days\"\n * here, vs. its \"last7\") -- a consumer with existing Playwright locators\n * keyed off those enum values needs to update them to this slug format,\n * or the caller needs a custom id mapping; not attempted here since no\n * generic per-option id override existed to build on. */\nfunction slug(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/(^-|-$)/g, \"\");\n}\n\n/**\n * @pattern DateRangeFilter\n * @description Date-range control -- the two-line chip (caption + value) with\n * a chevron that opens a two-pane picker: preset shortcuts on the left, a\n * dual-month calendar with range highlighting on the right, Start/End fields,\n * and Cancel/Apply. Shared by Creative Intel and the Account Review.\n * @tokens rounded-control, rounded-card, border-border-default, border-border-strong,\n * bg-surface, bg-input, bg-subtle, bg-ai-tint, bg-brand-primaryAction,\n * shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary,\n * hover:bg-subtle, hover:text-text-primary, focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior Escape and outside-click both close the popup. Opening always\n * resets the draft (shortcut/start/end/visible month) to the last committed\n * values, so a previous unsaved edit never lingers into the next open. Only\n * the Apply button commits -- Cancel, Escape, and outside-click all discard\n * the draft silently.\n * @a11y Trigger is a <button> with aria-expanded and an aria-label from the\n * caption; the panel is role=\"dialog\" and Escape closes it. Focus is not\n * moved into the panel, so it is reached by tabbing.\n * @usage\n * ```tsx\n * <DateRangeFilter caption=\"Date Range\" defaultValue=\"Rolling 6 months\" onChange={setRange} />\n * <DateRangeFilter presetSet=\"creativeIntel\" defaultValue=\"Last 7 days\" onChange={setRange} />\n * <DateRangeFilter presetSet=\"creativeIntel\" value={preset} range={[start, end]} onChange={setPreset} onRangeChange={(s, e) => setRange({ start: s, end: e })} />\n * ```\n */\nexport interface DateRangeFilterProps {\n /** Static label shown above the value when `showDates` is false. */\n caption?: string;\n /** Initial preset (matched case-insensitively against the active preset set) or, if unmatched, treated as a custom label. Ignored once `value`/`range` are given -- see those. */\n defaultValue?: string;\n /**\n * Controlled mode: the parent owns the committed preset/range instead of\n * this component tracking it internally. Give both `value` and `range`\n * together to enable it -- omit both (the default) for the original\n * uncontrolled behavior, where `defaultValue` seeds the initial state and\n * `onChange`/`onRangeChange` are fire-and-forget notifications. In\n * controlled mode the chip's displayed value/dates always reflect these\n * props directly, so the parent must call `onChange`/`onRangeChange` and\n * feed the result back for the chip to update after Apply -- the same\n * contract as a controlled `<input value onChange>`.\n */\n value?: string;\n /** Controlled mode's resolved range -- see `value`. */\n range?: [Date, Date];\n /** Which edge of the trigger the popup aligns to. */\n align?: \"left\" | \"right\";\n /** Fired on Apply with the chip's new display value. */\n onChange?: (value: string) => void;\n /** Fired on Apply (and once on mount, uncontrolled only) with the resolved start/end dates -- e.g. to drive dependent table columns. */\n onRangeChange?: (start: Date, end: Date) => void;\n /** Show the resolved start-end dates in the chip instead of the preset name. */\n showDates?: boolean;\n /** Use an abbreviated date format (e.g. \"Dec 1, 2025 - Jun 24, 2026\") for the dates line. */\n shortDates?: boolean;\n /** Optional leading icon rendered before the caption/value stack. */\n icon?: React.ReactNode;\n /** 'creativeIntel' swaps in the day-level shortcut list (Today/Yesterday/Last N days/All available history) used by that dashboard. */\n presetSet?: \"default\" | \"creativeIntel\";\n /** Prefix for data-testid attributes on the trigger, popover, each preset option, and Cancel/Apply. Omit for no test-id wiring. */\n testIdPrefix?: string;\n}\n\nexport function DateRangeFilter({\n caption = \"Date Range\",\n defaultValue,\n value: controlledValue,\n range: controlledRange,\n align = \"left\",\n onChange,\n onRangeChange,\n showDates = false,\n shortDates = false,\n icon,\n presetSet = \"default\",\n testIdPrefix,\n}: DateRangeFilterProps) {\n const controlled = controlledValue !== undefined && controlledRange !== undefined;\n const SHORTCUTS = presetSet === \"creativeIntel\" ? CREATIVE_INTEL_SHORTCUTS : DEFAULT_SHORTCUTS;\n const today = useMemo(() => new Date(), []);\n const initShortcut = matchShortcut(SHORTCUTS, controlled ? controlledValue : defaultValue);\n const initRange = (\n controlled ? controlledRange! : (presetRange(initShortcut === \"Custom\" ? \"Rolling 12 months\" : initShortcut, today) as [Date, Date])\n );\n const dateLine = (s: Date, e: Date) => (shortDates ? `${fmt(s)} – ${fmt(e)}` : fullRangeLabel(s, e));\n\n const [open, setOpen] = useState(false);\n // Uncontrolled-only: the chip's own tracked value/dates line, seeded from\n // defaultValue. In controlled mode the chip reads controlledValue/\n // controlledRange directly every render instead (see `displayValue`/\n // `displayDatesLine` below) -- these two pieces of state are simply unused\n // then, since the parent's props are the single source of truth.\n const [uncontrolledValue, setUncontrolledValue] = useState(\n showDates ? presetLabel(initShortcut) : defaultValue || \"Last 7 days\"\n );\n const [uncontrolledDatesLine, setUncontrolledDatesLine] = useState(dateLine(initRange[0], initRange[1]));\n // Uncontrolled-only committed state (what the chip reflects between opens).\n // In controlled mode, controlledValue/controlledRange play this role\n // instead -- always current, since they come from the parent every render,\n // never going stale the way a ref seeded once at mount would.\n const committed = useRef({ shortcut: initShortcut, start: initRange[0], end: initRange[1] });\n const displayValue = controlled ? (showDates ? presetLabel(initShortcut) : controlledValue!) : uncontrolledValue;\n const displayDatesLine = controlled ? dateLine(initRange[0], initRange[1]) : uncontrolledDatesLine;\n // draft state (inside the open popup)\n const [shortcut, setShortcut] = useState<Shortcut>(initShortcut);\n const [start, setStart] = useState<Date | null>(initRange[0]);\n const [end, setEnd] = useState<Date | null>(initRange[1]);\n const [leftMonth, setLeftMonth] = useState<Date>(new Date(initRange[0].getFullYear(), initRange[0].getMonth(), 1));\n const ref = useRef<HTMLDivElement>(null);\n\n // Emit the initial range once on mount so dependent views start in sync --\n // uncontrolled only. A controlled caller already owns and passes in the\n // starting range itself, so there's nothing to announce.\n useEffect(() => {\n if (controlled) return;\n onRangeChange?.(committed.current.start, committed.current.end);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!open) return;\n // Reset the draft to the committed value each time it opens -- from\n // props directly in controlled mode (always current), from the internal\n // ref otherwise.\n const committedShortcut = controlled ? initShortcut : committed.current.shortcut;\n const committedStart = controlled ? initRange[0] : committed.current.start;\n const committedEnd = controlled ? initRange[1] : committed.current.end;\n setShortcut(committedShortcut);\n setStart(committedStart);\n setEnd(committedEnd);\n setLeftMonth(new Date(committedStart.getFullYear(), committedStart.getMonth(), 1));\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n const choosePreset = (key: Shortcut) => {\n setShortcut(key);\n if (key === \"Custom\") return;\n const r = presetRange(key, today);\n if (r) { setStart(r[0]); setEnd(r[1]); setLeftMonth(new Date(r[0].getFullYear(), r[0].getMonth(), 1)); }\n };\n\n const pickDay = (d: Date) => {\n setShortcut(\"Custom\");\n if (!start || (start && end)) { setStart(d); setEnd(null); }\n else if (d < start) { setEnd(start); setStart(d); }\n else setEnd(d);\n };\n\n const apply = () => {\n const s = start || initRange[0];\n const e = end || s;\n const v = showDates ? presetLabel(shortcut) : shortcut === \"Custom\" ? `${fmt(s)} — ${fmt(e)}` : shortcut;\n // Uncontrolled only: track the new committed value/dates ourselves. In\n // controlled mode this is the parent's job -- it owns `value`/`range`\n // and is expected to feed the updated ones back in via its own state,\n // same contract as a controlled <input value onChange>.\n if (!controlled) {\n committed.current = { shortcut, start: s, end: e };\n setUncontrolledValue(v);\n setUncontrolledDatesLine(dateLine(s, e));\n }\n onChange?.(v);\n onRangeChange?.(s, e);\n setOpen(false);\n };\n\n // Inlined here rather than depending on the (not-yet-migrated) ChipTrigger\n // pattern's `chipTriggerClass` -- this package can't import an app-local\n // helper from insights-studio-prototype, and the trigger visual is simple\n // enough not to need a shared abstraction of its own yet.\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-trigger`}\n onClick={() => setOpen((v) => !v)}\n aria-expanded={open}\n className=\"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n {icon && <span className=\"shrink-0 text-text-tertiary\">{icon}</span>}\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className={showDates ? \"text-[11px] text-text-tertiary\" : \"text-[10px] uppercase tracking-wide text-text-tertiary\"}>\n {showDates ? displayDatesLine : caption}\n </span>\n <span className=\"text-[12px] font-medium text-text-primary\">{displayValue}</span>\n </span>\n <ChevronDown size={14} aria-hidden=\"true\" className={`shrink-0 text-text-secondary transition-transform ${open ? \"rotate-180\" : \"\"}`} />\n </button>\n\n {open && (\n <div\n data-testid={testIdPrefix && `${testIdPrefix}-popover`}\n className={`absolute top-[calc(100%+8px)] z-30 flex overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay ${align === \"right\" ? \"right-0\" : \"left-0\"}`}\n role=\"dialog\"\n aria-label=\"Select date range\"\n >\n {/* Shortcuts rail */}\n <div className=\"flex w-44 shrink-0 flex-col gap-0.5 border-r border-border-default p-2\">\n {SHORTCUTS.map((s) => (\n <button\n key={s}\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-option-${slug(s)}`}\n onClick={() => choosePreset(s)}\n className={`rounded-control px-3 py-2 text-left text-[13px] font-medium transition-colors ${\n shortcut === s ? \"bg-subtle text-text-primary\" : \"text-text-secondary hover:bg-subtle hover:text-text-primary\"\n }`}\n >\n {s}\n </button>\n ))}\n </div>\n\n {/* Calendar pane */}\n <div className=\"flex flex-col p-4\">\n {/* Start / End fields */}\n <div className=\"flex items-end gap-3\">\n <Field label=\"Start Date\" value={start ? fmt(start) : \"—\"} />\n <span className=\"pb-2.5 text-text-tertiary\">{\"—\"}</span>\n <Field label=\"End Date\" value={end ? fmt(end) : start ? fmt(start) : \"—\"} />\n </div>\n\n <div className=\"my-4 border-t border-border-default\" />\n\n {/* Two months */}\n <div className=\"flex gap-8\">\n {[0, 1].map((offset) => {\n const m = addMonths(leftMonth, offset);\n const grid = monthGrid(m.getFullYear(), m.getMonth());\n return (\n <div key={offset} className=\"w-[252px]\">\n <div className=\"mb-2 flex items-center justify-between\">\n {offset === 0 ? (\n <NavBtn onClick={() => setLeftMonth(addMonths(leftMonth, -1))} aria-label=\"Previous month\"><ChevronLeft size={16} /></NavBtn>\n ) : <span className=\"h-7 w-7\" />}\n <span className=\"text-[15px] font-semibold text-text-primary\">{MONTHS[m.getMonth()]} {m.getFullYear()}</span>\n {offset === 1 ? (\n <NavBtn onClick={() => setLeftMonth(addMonths(leftMonth, 1))} aria-label=\"Next month\"><ChevronRight size={16} /></NavBtn>\n ) : <span className=\"h-7 w-7\" />}\n </div>\n <div className=\"grid grid-cols-7\">\n {WEEKDAYS.map((w) => (\n <div key={w} className=\"flex h-8 items-center justify-center text-[12px] font-semibold text-text-secondary\">{w}</div>\n ))}\n {grid.map((d, i) => {\n const inMonth = d.getMonth() === m.getMonth();\n const hasRange = !!(start && end);\n const isStart = !!start && sameDay(d, start);\n const isEnd = end ? sameDay(d, end) : isStart && !end;\n const inRange = hasRange && d >= startOfDay(start!) && d <= startOfDay(end!);\n const single = isStart && isEnd;\n const endpoint = isStart || (!!end && isEnd);\n // band geometry\n let band = \"\";\n if (inRange && !single) {\n if (isStart) band = \"left-1/2 right-0\";\n else if (end && isEnd) band = \"left-0 right-1/2\";\n else band = \"left-0 right-0\";\n }\n return (\n <button key={i} type=\"button\" onClick={() => pickDay(d)} className=\"relative flex h-9 items-center justify-center\">\n {band && <span className={`absolute inset-y-[3px] bg-ai-tint ${band}`} aria-hidden=\"true\" />}\n <span\n className={`relative z-10 flex h-8 w-8 items-center justify-center rounded-full text-[13px] tabular-nums ${\n endpoint ? \"bg-brand-primaryAction font-semibold text-white\" : inMonth ? \"text-text-primary hover:bg-subtle\" : \"text-text-tertiary\"\n }`}\n >\n {d.getDate()}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Actions */}\n <div className=\"mt-4 flex justify-end gap-2\">\n <button type=\"button\" data-testid={testIdPrefix && `${testIdPrefix}-cancel`} onClick={() => setOpen(false)} className=\"rounded-control border border-border-default bg-surface px-5 py-2 text-[13px] font-semibold text-text-primary transition-colors hover:bg-subtle\">Cancel</button>\n <button type=\"button\" data-testid={testIdPrefix && `${testIdPrefix}-apply`} onClick={apply} className=\"rounded-control bg-brand-primaryAction px-5 py-2 text-[13px] font-semibold text-white transition-[filter] hover:brightness-110\">Apply</button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction Field({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-[12px] font-medium text-text-secondary\">{label}</span>\n <div className=\"flex h-10 min-w-[140px] items-center rounded-control border border-border-default bg-input px-3 text-[14px] font-medium text-text-primary\">{value}</div>\n </div>\n );\n}\n\nfunction NavBtn({ children, onClick, ...rest }: { children: React.ReactNode; onClick: () => void; \"aria-label\": string }) {\n return (\n <button type=\"button\" onClick={onClick} className=\"flex h-7 w-7 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary\" {...rest}>\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { AlertCircle, Check, ChevronDown, Search } from \"lucide-react\";\n\n/**\n * @pattern SearchBar\n * @description Filter-bar keyword search. 'default' is a plain keyword\n * input; 'filterable' adds an attached match-type dropdown sharing one\n * bordered control, mirroring the legacy Creative Intel search + match-type\n * modal (Any Word/Exact Match/Contextual/Ad Code), including the Or/And\n * sub-choice nested under Any Word.\n * @tokens rounded-control, border-border-strong, bg-input, text-text-primary,\n * text-text-tertiary, hover:bg-subtle, bg-brand-primaryAction, bg-subtle,\n * bg-surface, border-brand-primaryAction, border-border-default,\n * border-border-interactive, focus-visible:outline-border-focus,\n * hover:text-text-primary, placeholder:text-text-tertiary, rounded-card,\n * rounded-full, shadow-overlay, text-brand-primaryAction, text-text-secondary\n * @variant default - Default. Plain keyword input, no match-type control.\n * @variant filterable - Adds an attached match-type dropdown sharing one\n * bordered control, mirroring the legacy Creative Intel search + match-type\n * modal (Any Word/Exact Match/Contextual/Ad Code), including the Or/And\n * sub-choice nested under Any Word.\n * @dependencies lucide-react\n * @behavior The match-type dropdown ('filterable' variant) closes on Escape\n * and outside click. Each mode row is a real `radio` role, with a nested\n * Or/And sub-choice under Any Word and its own click-to-toggle info tooltip.\n * The text input carries an `aria-label` derived from `placeholder` — the\n * wrapping `<label>` has no visible text content (just an icon and the\n * input), so it grants the input no accessible name on its own.\n * @a11y The <input> takes its accessible name from `ariaLabel`. The match-mode\n * popover is a radio group (role=\"radio\" + aria-checked) and its trigger\n * reports aria-expanded. Escape closes the popover only, leaving focus in\n * the field -- a consumer nesting this inside another dismissible layer\n * must sequence the two dismissals itself.\n * @usage\n * ```tsx\n * <SearchBar value={query} onChange={setQuery} />\n * <SearchBar variant=\"filterable\" value={query} onChange={setQuery} matchValue={matchValue} onMatchChange={setMatchValue} />\n * ```\n */\nexport type SearchBarVariant = \"default\" | \"filterable\";\n\nexport type SearchMatchMode = \"anyWord\" | \"exactMatch\" | \"contextual\" | \"adCode\";\n\nexport interface SearchMatchValue {\n mode: SearchMatchMode;\n /** Only meaningful when mode === 'anyWord'. */\n wordJoin: \"Or\" | \"And\";\n}\n\nexport const DEFAULT_SEARCH_MATCH: SearchMatchValue = { mode: \"anyWord\", wordJoin: \"Or\" };\n\nconst MODE_LABEL: Record<SearchMatchMode, string> = {\n anyWord: \"Any Word\",\n exactMatch: \"Exact Match\",\n contextual: \"Contextual\",\n adCode: \"Ad Code\",\n};\n\n/** Joins conditional class fragments — this package has no clsx/tailwind-merge dependency, and none of the classes below actually conflict, so a plain filter+join is enough. */\nfunction cx(...classes: Array<string | false | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\nexport interface SearchBarProps {\n /** Input placeholder text. Also used as the input's `aria-label`. */\n placeholder?: string;\n value?: string;\n onChange?: (v: string) => void;\n /** 'default' is a plain keyword input; 'filterable' adds the match-type dropdown. */\n variant?: SearchBarVariant;\n /** The 'filterable' variant's dropdown state. */\n matchValue?: SearchMatchValue;\n onMatchChange?: (v: SearchMatchValue) => void;\n className?: string;\n /**\n * Optional prefix for `data-testid` attributes on the input, the\n * match-type trigger/popover, each mode row, and the Or/And radio pair\n * (e.g. `${testIdPrefix}-search`, `${testIdPrefix}-mode-trigger`,\n * `${testIdPrefix}-mode-anyWord`, `${testIdPrefix}-word-join-or`). Omit\n * entirely for no test-id wiring at all -- added specifically so an\n * existing Playwright suite keyed off these ids (mr-clientapps'\n * `KeywordSearchBar`) doesn't lose its locators when swapped over to\n * this shared component.\n */\n testIdPrefix?: string;\n}\n\nexport function SearchBar({\n placeholder = \"Search…\",\n value,\n onChange,\n variant = \"default\",\n matchValue,\n onMatchChange,\n className,\n testIdPrefix,\n}: SearchBarProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n };\n }, [open]);\n\n const showMatch = variant === \"filterable\" && matchValue;\n\n return (\n <div\n className={cx(\n \"flex h-11 min-w-[200px] flex-1 items-stretch rounded-control border border-border-strong bg-input\",\n className\n )}\n >\n <label className=\"flex min-w-0 flex-1 items-center gap-2 px-2.5\">\n <Search size={15} aria-hidden=\"true\" className=\"shrink-0 text-text-tertiary\" />\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange?.(e.target.value)}\n placeholder={placeholder}\n aria-label={placeholder}\n data-testid={testIdPrefix && `${testIdPrefix}-search`}\n className=\"min-w-0 flex-1 bg-transparent text-[13px] text-text-primary outline-hidden placeholder:text-text-tertiary\"\n />\n </label>\n {showMatch && (\n // border-border-default, not the bare `border-border` both source\n // implementations used -- confirmed by actually compiling against\n // @mediaradar/design-tokens' real published theme.css (not assumed):\n // there is no bare `--color-border` in that file, only the\n // -default/-interactive/-focus/-focusSoft/-strong suffixed variants,\n // so `border-border` silently generates no utility at all there. It\n // only \"worked\" in each source app because each one separately\n // defines its own local `border-border` alias outside the shared\n // token package (insights-studio-prototype's own src/index.css;\n // mr-clientapps' own tailwind.config.ts `colors.border.DEFAULT`) --\n // an alias this shared component can't rely on existing.\n <div className=\"relative shrink-0 border-l border-border-default\" ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-mode-trigger`}\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-haspopup=\"dialog\"\n className=\"flex h-full items-center gap-1 px-2.5 text-[13px] font-medium text-text-primary transition-colors hover:bg-subtle\"\n >\n {matchValue.mode === \"anyWord\" ? `${MODE_LABEL.anyWord} (${matchValue.wordJoin})` : MODE_LABEL[matchValue.mode]}\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n {open && (\n <div\n role=\"dialog\"\n aria-label=\"Search match type\"\n data-testid={testIdPrefix && `${testIdPrefix}-mode-popover`}\n // shadow-overlay, not mr-clientapps' `shadow-2` -- same stale-\n // local-name issue InfoTip's reconciliation already found:\n // `shadow-2` doesn't exist anywhere in @mediaradar/design-tokens\n // (only shadow-raised/shadow-overlay do), it's a value hand-\n // copied into mr-clientapps' own tailwind.config.ts `boxShadow`\n // extension rather than referencing the shared token.\n className=\"absolute right-0 top-[calc(100%+8px)] z-50 w-[400px] rounded-card border border-border-default bg-surface p-3 shadow-overlay\"\n >\n <div role=\"radiogroup\" aria-label=\"Search match type\" className=\"flex flex-col\">\n <ModeRow\n title=\"Any Word Text Search\"\n selected={matchValue.mode === \"anyWord\"}\n onSelect={() => onMatchChange?.({ mode: \"anyWord\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-anyWord`}\n description={\n <>\n Find creatives that contain your keyword(s) using an &ldquo;Or&rdquo; (match any) or &ldquo;And&rdquo; (match all)\n conditional in any order.\n </>\n }\n infoText=\"The Or/And choice applies only when Any Word is the active search mode.\"\n extra={\n <span className=\"flex items-center gap-3\">\n <RadioOption\n label=\"Or\"\n checked={matchValue.wordJoin === \"Or\"}\n onSelect={() => onMatchChange?.({ mode: \"anyWord\", wordJoin: \"Or\" })}\n testId={testIdPrefix && `${testIdPrefix}-word-join-or`}\n />\n <RadioOption\n label=\"And\"\n checked={matchValue.wordJoin === \"And\"}\n onSelect={() => onMatchChange?.({ mode: \"anyWord\", wordJoin: \"And\" })}\n testId={testIdPrefix && `${testIdPrefix}-word-join-and`}\n />\n </span>\n }\n />\n <Divider />\n <ModeRow\n title=\"Exact Match Text Search\"\n selected={matchValue.mode === \"exactMatch\"}\n onSelect={() => onMatchChange?.({ mode: \"exactMatch\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-exactMatch`}\n description=\"Find creatives that mention your exact keyword phrase.\"\n infoText=\"Keywords are matched as a single contiguous phrase, in the order you typed them.\"\n />\n <Divider />\n <ModeRow\n title=\"Contextual Search\"\n badge=\"Beta\"\n selected={matchValue.mode === \"contextual\"}\n onSelect={() => onMatchChange?.({ mode: \"contextual\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-contextual`}\n description=\"Find creatives that may contain OR have similar meaning as your keyword(s).\"\n infoText=\"Uses semantic matching, so results can include related terms even when the exact keyword isn't present.\"\n />\n <Divider />\n <ModeRow\n title=\"Ad Code Search\"\n selected={matchValue.mode === \"adCode\"}\n onSelect={() => onMatchChange?.({ mode: \"adCode\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-adCode`}\n description=\"Find creatives based on a list of one or more ad codes that you provide.\"\n infoText=\"Separate multiple ad codes with a comma or a new line.\"\n />\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction Divider() {\n return <div className=\"my-2.5 border-t border-border-default\" aria-hidden=\"true\" />;\n}\n\n/** One selectable search-mode block — title (+ optional badge/extra controls), description, and a trailing checkmark when active. */\nfunction ModeRow({\n title,\n badge,\n extra,\n description,\n infoText,\n selected,\n onSelect,\n testId,\n}: {\n title: string;\n badge?: string;\n extra?: React.ReactNode;\n description: React.ReactNode;\n infoText: string;\n selected: boolean;\n onSelect: () => void;\n testId?: string;\n}) {\n return (\n <div\n role=\"radio\"\n tabIndex={0}\n aria-checked={selected}\n data-testid={testId}\n onClick={onSelect}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect();\n }\n }}\n // outline-solid, not a bare `outline` (mr-clientapps' spelling) --\n // same fallback InfoTip's reconciliation already flagged: bare\n // `outline` only renders solid because Tailwind v4's `--tw-outline-\n // style` custom property happens to declare `solid` as its @property\n // initial-value, not because the utility sets it explicitly. Confirmed\n // by compiling both against the real theme.css.\n className=\"flex cursor-pointer flex-col items-stretch gap-1 rounded-control p-1.5 text-left transition-colors hover:bg-subtle focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"flex items-center gap-1\">\n <span className=\"text-[14px] font-semibold text-text-primary\">{title}</span>\n <RowInfoTip text={infoText} />\n </span>\n {badge && (\n <span className=\"rounded-full bg-subtle px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-text-secondary\">\n {badge}\n </span>\n )}\n {extra}\n </div>\n {selected && <Check size={16} strokeWidth={2.5} aria-hidden=\"true\" className=\"shrink-0 text-brand-primaryAction\" />}\n </div>\n <span className=\"block text-[12.5px] leading-snug text-text-secondary\">{description}</span>\n </div>\n );\n}\n\n/** Single radio-style choice used inline in the Any Word row (Or / And). */\nfunction RadioOption({\n label,\n checked,\n onSelect,\n testId,\n}: {\n label: string;\n checked: boolean;\n onSelect: () => void;\n testId?: string;\n}) {\n return (\n <button\n type=\"button\"\n data-testid={testId}\n onClick={(e) => {\n e.stopPropagation();\n onSelect();\n }}\n role=\"radio\"\n aria-checked={checked}\n className=\"flex items-center gap-1.5 text-[13px] font-medium text-text-primary\"\n >\n <span\n className={cx(\n \"flex h-4 w-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors\",\n checked ? \"border-brand-primaryAction\" : \"border-border-interactive\"\n )}\n >\n {/*\n text-brand-primaryAction / bg-brand-primaryAction / border-brand-\n primaryAction throughout this file, not insights-studio-prototype's\n `text-(--color-brand-primary-action)` (Tailwind v4 arbitrary-\n property syntax referencing a literal, dash-cased CSS variable).\n Confirmed by compiling against the real, published theme.css: that\n exact variable name is never defined there -- only the camelCase\n `--color-brand-primaryAction` is (theme.css line 63). The dash-case\n form only resolves in prototype today because prototype's own\n src/index.css / src/styles/tokens.css separately hand-define that\n alias; mr-clientapps' `text-brand-primaryAction` (its own\n tailwind.config.ts extends `colors.brand.primaryAction` the same\n way) happens to already match the shared package's real name.\n */}\n {checked && <span className=\"h-2 w-2 rounded-full bg-brand-primaryAction\" />}\n </span>\n {label}\n </button>\n );\n}\n\n/** Small click-to-toggle tooltip on an alert-circle glyph, trailing a mode's description. */\nfunction RowInfoTip({ text }: { text: string }) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLSpanElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n return (\n <span className=\"relative inline-flex shrink-0 items-center\" ref={ref}>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setOpen((o) => !o);\n }}\n aria-label=\"More information\"\n aria-expanded={open}\n className=\"inline-flex text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <AlertCircle size={13} aria-hidden=\"true\" />\n </button>\n {open && (\n <span\n role=\"tooltip\"\n className=\"absolute left-0 top-[calc(100%+6px)] z-40 w-[220px] rounded-control border border-border-default bg-surface px-2.5 py-1.5 text-[11.5px] font-normal leading-snug text-text-secondary shadow-overlay\"\n >\n {text}\n </span>\n )}\n </span>\n );\n}\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\n\n/**\n * @pattern SectionRail\n * @description Generic titled section wrapper for a row of cards — a\n * horizontal scroll rail on mobile/tablet (snap, bleeds to edges), a\n * left-aligned 4-column grid on desktop. Card width is handled here, not on\n * the card itself, so cards stay layout-agnostic; it works with any\n * `children`. Real call sites vary: a fixed 4-item row that fills the\n * desktop grid exactly, or a variable-length list with no \"view all\" link\n * at all — both need to keep working without the row assuming a count.\n * @tokens text-text-primary, text-text-secondary, text-text-link,\n * rounded-control, rounded-sm, border-border-default, focus-visible:outline-solid,\n * focus-visible:outline-border-focus, hover:bg-subtle, hover:text-text-primary,\n * tracking-tight, font-serif\n * @dependencies lucide-react\n * @behavior Card width lives on the row, not the card: a fixed 268px per\n * card in rail mode, capped at 320px per column in the lg+ grid, so cards\n * stay layout-agnostic. The \"view all\" link only renders when both\n * `viewAllLabel` and `viewAllHref` are given — either alone hides it, rather\n * than falling back to a dead `href=\"#\"`. Prev/next arrows are hidden below\n * `sm` (swipe is the native affordance there) and at `lg`+ (the grid shows\n * every card, nothing left to scroll to). `viewAllHref` renders as a plain\n * anchor rather than a framework router Link — this package has no router\n * peer dependency, and the two consuming apps disagree on one (react-router-dom\n * vs next/link); a plain anchor is the one thing that works unmodified in both.\n * @a11y Rail items are buttons and take their accessible name from `ariaLabel`,\n * since several render icon-only. Without it they announce as unnamed\n * buttons.\n * @usage\n * ```tsx\n * <SectionRail title=\"Sports\" subtitle=\"Your tracked leagues\" viewAllLabel=\"View all\" viewAllHref=\"/sports\">\n * {items.map((i) => <Card key={i.id}>{i.name}</Card>)}\n * </SectionRail>\n * ```\n */\nexport interface SectionRailProps {\n /** Section heading. */\n title: string;\n /** Use the serif display treatment instead of the default sans heading. */\n titleSerif?: boolean;\n /** Supporting line under the title. */\n subtitle: string;\n /** Label for the \"view all\" link. Has no effect unless `viewAllHref` is also given. */\n viewAllLabel?: string;\n /** Route the \"view all\" link points to. Has no effect unless `viewAllLabel` is also given. */\n viewAllHref?: string;\n /** The row's cards. Any content works — width is handled by the row, not the card. */\n children: React.ReactNode;\n}\n\nexport function SectionRail({\n title,\n titleSerif,\n subtitle,\n viewAllLabel,\n viewAllHref,\n children,\n}: SectionRailProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const scroll = (direction: -1 | 1) => {\n scrollRef.current?.scrollBy({ left: direction * 320, behavior: \"smooth\" });\n };\n\n return (\n <section className=\"flex flex-col gap-4\">\n <header className=\"flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between\">\n {/* Title block */}\n <div>\n <h2\n className={\n titleSerif\n ? \"font-serif text-2xl font-normal tracking-tight text-text-primary sm:text-[28px]\"\n : \"text-xl font-medium tracking-tight text-text-primary sm:text-2xl\"\n }\n >\n {title}\n </h2>\n <p className=\"mt-1 text-sm text-text-secondary\">{subtitle}</p>\n </div>\n\n {/* Controls — link + scroll arrows.\n Arrows hidden on mobile (swipe is natural) AND on lg+ (no scroll, all cards visible). */}\n <div className=\"flex items-center gap-2\">\n {viewAllLabel && viewAllHref && (\n <a\n href={viewAllHref}\n className=\"text-sm font-medium text-text-link transition-colors hover:underline focus-visible:rounded-sm focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n {viewAllLabel} →\n </a>\n )}\n <button\n type=\"button\"\n onClick={() => scroll(-1)}\n aria-label=\"Previous\"\n className=\"hidden h-10 w-10 items-center justify-center rounded-control border border-border-default text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary sm:flex lg:hidden\"\n >\n <ChevronLeft size={16} />\n </button>\n <button\n type=\"button\"\n onClick={() => scroll(1)}\n aria-label=\"Next\"\n className=\"hidden h-10 w-10 items-center justify-center rounded-control border border-border-default text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary sm:flex lg:hidden\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n </header>\n\n {/* Card row.\n - Mobile / tablet: horizontal scroll rail with fixed 268px cards (snap, bleed to edges).\n - Desktop (lg+): 4-column grid, cards stretch to fill.\n The width handling lives here (on the row), not on the Card, so cards stay layout-agnostic. */}\n <div\n ref={scrollRef}\n className=\"flex gap-4 overflow-x-auto scroll-smooth pb-2 snap-x snap-mandatory scrollbar-none [&::-webkit-scrollbar]:hidden -mx-4 px-4 sm:mx-0 sm:px-0 *:w-[268px] *:shrink-0 *:snap-start lg:grid lg:grid-cols-[repeat(4,minmax(0,320px))] lg:gap-5 lg:overflow-visible lg:justify-start lg:*:w-auto lg:*:shrink lg:*:snap-none\"\n >\n {children}\n </div>\n </section>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Check, ChevronDown } from \"lucide-react\";\nimport { InfoTip } from \"./InfoTip\";\n\nconst FINAL_ONLY_TEXT =\n \"Trims time periods to data that has finalized across the selected media formats. Some formats (e.g. Network TV and Cinema) finalize later, so the most recent periods may still change. Turn on for stable, report-ready numbers.\";\n\n/** Joins conditional class fragments -- this package has no clsx/tailwind-merge dependency. */\nfunction cx(...classes: Array<string | false | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * @pattern DataScopeFilter\n * @description \"Data\" scope chip -- toggles the filter bar between All data\n * and Final-only data (data that's finalized across the selected media\n * formats, for stable report-ready numbers). One boolean, one control,\n * shared across every dashboard that has this data-finality concept\n * (Publisher Intel, Opportunities, Sports).\n * @tokens rounded-control, border-border-strong, bg-input, hover:bg-subtle,\n * hover:text-text-primary, focus-visible:outline-border-focus, rounded-card,\n * border-border-default, bg-surface, shadow-overlay, text-text-primary,\n * text-text-secondary, text-text-tertiary, text-brand-primaryAction\n * @dependencies lucide-react\n * @behavior Escape and outside-click both close the popover. The \"Final\n * only\" option's info tooltip is a real InfoTip in hover mode, rendered as a\n * sibling of the option button rather than nested inside it -- InfoTip\n * renders its own `<button>`, and a button nested inside another button is\n * invalid HTML that breaks click targeting (confirmed against how\n * mr-clientapps-insights-studio's own equivalent, `ChipOption`, already\n * avoids exactly this by rendering its InfoTip as a sibling, not a child).\n * @a11y Trigger is a <button> with aria-expanded and aria-haspopup; the menu is\n * role=\"listbox\" with role=\"option\" rows carrying aria-selected. Escape\n * closes it. Use the listbox semantics as given -- adding a second role to\n * the wrapper breaks the option/listbox relationship.\n * @usage\n * ```tsx\n * <DataScopeFilter value={finalOnly} onChange={setFinalOnly} />\n * ```\n */\nexport interface DataScopeFilterProps {\n value: boolean;\n onChange: (v: boolean) => void;\n /** Which edge of the trigger the popover aligns to. Both known consumers\n * anchor this at the right edge of a filter bar, hence the default. */\n align?: \"left\" | \"right\";\n}\n\nexport function DataScopeFilter({ value, onChange, align = \"right\" }: DataScopeFilterProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n const display = value ? \"Final only\" : \"All\";\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n window.addEventListener(\"mousedown\", onDown);\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"mousedown\", onDown);\n window.removeEventListener(\"keydown\", onKey);\n };\n }, [open]);\n\n const choose = (v: boolean) => {\n onChange(v);\n setOpen(false);\n };\n\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n className=\"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">Data</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{display}</span>\n </span>\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div\n role=\"listbox\"\n aria-label=\"Data\"\n className={cx(\n \"absolute top-[calc(100%+8px)] z-30 min-w-[220px] overflow-hidden rounded-card border border-border-default bg-surface p-1 shadow-overlay\",\n align === \"right\" ? \"right-0\" : \"left-0\"\n )}\n >\n <Option label=\"All\" selected={!value} onClick={() => choose(false)} />\n <Option label=\"Final only\" selected={value} onClick={() => choose(true)} hint={FINAL_ONLY_TEXT} />\n </div>\n )}\n </div>\n );\n}\n\nfunction Option({\n label,\n selected,\n onClick,\n hint,\n}: {\n label: string;\n selected: boolean;\n onClick: () => void;\n hint?: string;\n}) {\n const option = (\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n onClick={onClick}\n className={cx(\n \"flex items-center gap-2 rounded-control px-2.5 py-2 text-left text-[13px] transition-colors hover:bg-subtle\",\n hint ? \"flex-1\" : \"w-full\",\n selected ? \"font-semibold text-text-primary\" : \"text-text-secondary\"\n )}\n >\n <Check size={14} aria-hidden=\"true\" className={cx(\"shrink-0 text-brand-primaryAction\", !selected && \"invisible\")} />\n {label}\n </button>\n );\n\n if (!hint) return option;\n\n return (\n <div className=\"flex items-center pr-2.5\">\n {option}\n <InfoTip text={hint} trigger=\"hover\" label={`About ${label}`} />\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Check, ChevronDown } from \"lucide-react\";\n\n/** Joins conditional class fragments -- this package has no clsx/tailwind-merge dependency. */\nfunction cx(...classes: Array<string | false | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens, trims edge hyphens --\n * used for each option's data-testid (matches the convention already used\n * by DateRangeFilter/AdvertiserQuickFilter in this package). */\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\");\n}\n\n/**\n * @pattern SelectFilter\n * @description Single-select filter chip -- the caption-over-value trigger\n * shape shared with AdvertiserQuickFilter/DateRangeFilter, opening a\n * lightweight listbox of plain string options. Portal-rendered to\n * `document.body` so the popover is never clipped by a scrollable ancestor\n * (e.g. inside a modal) -- unlike this package's other chip popovers, none\n * of which are known to sit inside a clipping container today.\n * @tokens rounded-control, rounded-card, border-border-default,\n * border-border-strong, bg-input, bg-surface, shadow-overlay,\n * text-text-primary, text-text-secondary,\n * text-text-tertiary, hover:bg-subtle, hover:text-text-primary,\n * text-brand-primaryAction, focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior The popover is portal-rendered to document.body, so its own DOM\n * node isn't inside the trigger. The outside-click check tests both the\n * trigger and the popover explicitly for that reason -- treating the\n * popover as \"outside\" would close it on every option click before\n * `onChange` ever fires, so nothing would ever get selected. Selecting an\n * option commits immediately and closes -- there's no separate draft/Apply\n * step; Escape and outside-click just close without side effects.\n * @a11y Trigger is a <button>; the popover is role=\"listbox\" with role=\"option\"\n * rows carrying aria-selected. The trigger owns the accessible name via\n * the caption. The popover is not a focus trap and does not move focus on\n * open, so keyboard users tab into it; a consumer rendering it inside\n * another dismissible layer has to sequence the two dismissals itself.\n * @usage\n * ```tsx\n * <SelectFilter caption=\"Rank\" value={rankFilter} onChange={setRankFilter} options={['All', 'VP / Director', 'Manager', 'Coordinator']} />\n * <SelectFilter caption=\"Group by\" value={groupBy} onChange={setGroupBy} options={['Parent', 'Advertiser', 'Brand']} fullWidth testIdPrefix=\"dropdown-group-by\" />\n * ```\n */\nexport interface SelectFilterProps {\n caption: string;\n value: string;\n options: string[];\n onChange: (v: string) => void;\n /** Which edge of the trigger the popover aligns to. */\n align?: \"left\" | \"right\";\n /** Stretch the trigger (and the popover, when true) to fill its container. */\n fullWidth?: boolean;\n /** Extra classes merged onto the trigger button -- e.g. a background\n * override for a filter bar that isn't sitting on a filter-tray canvas. */\n className?: string;\n /**\n * Optional prefix for `data-testid` attributes on the trigger\n * (`${testIdPrefix}-trigger`), the popover (`${testIdPrefix}-popover`),\n * and each option (`${testIdPrefix}-option-<slugified-label>`). Omit\n * entirely for no test-id wiring at all -- added specifically so an\n * existing Playwright suite keyed off hardcoded ids (mr-clientapps'\n * `GroupBySelect`, e.g. `dropdown-group-by-option-parent`) can be re-keyed\n * to this shared component's ids rather than losing its locators outright.\n */\n testIdPrefix?: string;\n}\n\nexport function SelectFilter({\n caption,\n value,\n options,\n onChange,\n align = \"left\",\n fullWidth = false,\n className,\n testIdPrefix,\n}: SelectFilterProps) {\n const [open, setOpen] = useState(false);\n const [pos, setPos] = useState<{ top: number; left: number; width: number } | null>(null);\n const ref = useRef<HTMLDivElement>(null);\n // The popover is portaled to <body>, so it's not a DOM descendant of `ref`.\n // Without checking this too, every option click reads as \"outside\" and\n // closes the popover on mousedown -- before the click that fires onChange\n // ever reaches the (now-unmounted) option button, so selection never sticks.\n const popoverRef = useRef<HTMLDivElement>(null);\n\n const close = useCallback(() => setOpen(false), []);\n\n const reposition = useCallback(() => {\n if (!ref.current) return;\n const r = ref.current.getBoundingClientRect();\n setPos({ top: r.bottom + 8, left: align === \"right\" ? r.right - r.width : r.left, width: r.width });\n }, [align]);\n\n useLayoutEffect(() => {\n if (!open) return;\n reposition();\n }, [open, reposition]);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && close();\n const onClick = (e: MouseEvent) => {\n const t = e.target as Node;\n if (ref.current?.contains(t) || popoverRef.current?.contains(t)) return;\n close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"scroll\", reposition, true);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n window.removeEventListener(\"resize\", reposition);\n window.removeEventListener(\"scroll\", reposition, true);\n };\n }, [open, close, reposition]);\n\n return (\n <div className={cx(\"relative\", fullWidth && \"w-full\")} ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-trigger`}\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n className={cx(\n \"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n fullWidth && \"w-full justify-between\",\n className\n )}\n >\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">{caption}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open &&\n pos &&\n createPortal(\n <div\n ref={popoverRef}\n data-testid={testIdPrefix && `${testIdPrefix}-popover`}\n style={{ position: \"fixed\", top: pos.top, left: pos.left, width: fullWidth ? pos.width : undefined }}\n className={cx(\n \"z-[65] flex flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay\",\n !fullWidth && \"w-56\"\n )}\n role=\"listbox\"\n aria-label={caption}\n >\n <div className=\"max-h-[280px] overflow-y-auto p-1\">\n {options.map((o) => {\n const selected = o === value;\n return (\n <button\n key={o}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n data-testid={testIdPrefix && `${testIdPrefix}-option-${slug(o)}`}\n onClick={() => {\n onChange(o);\n close();\n }}\n className=\"flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle\"\n >\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center text-brand-primaryAction\">\n {selected && <Check size={15} strokeWidth={3} />}\n </span>\n <span\n className={cx(\"flex-1 text-[14px]\", selected ? \"font-semibold text-text-primary\" : \"text-text-primary\")}\n >\n {o}\n </span>\n </button>\n );\n })}\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { forwardRef, type ReactNode } from \"react\";\n\n/**\n * @pattern Card\n * @description Layout primitive for grouping content in a bordered, elevated\n * surface. Width is controlled by the parent container, not the Card itself,\n * so it works unchanged as a fixed-width rail item or a grid cell. Applies an\n * interactive hover treatment (deeper shadow) unless `staticCard` is set. An\n * optional `title` (+ `subtitle`/`action`) renders a standard header row and\n * switches the card into a padded content layout, replacing the header/body\n * shell mr-clientapps-insights-studio's own `CardShell` used to hand-roll.\n * @tokens rounded-card, border-border-default, bg-surface, shadow-raised,\n * hover:shadow-overlay, p-card-padding, text-text-primary, text-text-tertiary\n * @behavior Without `title`, children render directly as the card's only\n * content -- no padding is applied, so callers that need a full-bleed image\n * or gradient flush against the card edge (the common case in\n * insights-studio-prototype's rail/grid cards) stay in control of their own\n * inner layout, exactly as before this component grew a `title` prop. With\n * `title`, the header and children are wrapped together in the card's\n * standard padding, matching `CardShell`'s layout so it can be swapped in\n * directly. `staticCard` drops the hover-shadow transition for non-clickable\n * content (a KPI tile, a read-only summary) -- there's nothing to respond to.\n * @variant interactive - Default. Clickable/hoverable content -- deeper\n * shadow on hover signals it responds to the cursor.\n * @variant static - Set `staticCard`. Non-clickable content -- no hover\n * treatment.\n * @usage\n * ```tsx\n * <Card>\n * <h3>Title</h3>\n * <p>Body content</p>\n * </Card>\n * <Card staticCard>Non-interactive content</Card>\n * <Card title=\"Spend trend\" subtitle=\"Last 90 days\" action={<Link to=\"/spend\">View all</Link>}>\n * <SpendChart />\n * </Card>\n * ```\n */\nexport interface CardProps extends Omit<React.HTMLAttributes<HTMLElement>, \"title\"> {\n /** Disable interactive hover treatment (when card isn't clickable). */\n staticCard?: boolean;\n /**\n * Optional header title. Omit it (the default) to keep Card a bare,\n * unpadded surface -- set it to get a title/subtitle/action header row\n * plus the card's standard content padding, matching `CardShell`.\n */\n title?: string;\n /** Shown under `title` in a muted tertiary color. Ignored without `title`. */\n subtitle?: string;\n /** Trailing header content, e.g. a \"View all\" link. Ignored without `title`. */\n action?: ReactNode;\n /** Card body. Rendered edge to edge without `title`; inside the standard padding with it. */\n children?: ReactNode;\n}\n\nexport const Card = forwardRef<HTMLElement, CardProps>(function Card(\n { staticCard, title, subtitle, action, className, children, ...rest },\n ref\n) {\n return (\n <article\n ref={ref}\n className={[\n \"flex h-full flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-raised\",\n // Interactive hover: deeper drop shadow only -- no elevation/transform.\n !staticCard && \"group transition-shadow hover:shadow-overlay\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n {...rest}\n >\n {title ? (\n <div className=\"flex flex-1 flex-col p-card-padding\">\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <h3 className=\"text-[15px] font-semibold leading-snug text-text-primary\">{title}</h3>\n {subtitle && <p className=\"mt-0.5 text-[12px] leading-snug text-text-tertiary\">{subtitle}</p>}\n </div>\n {action && <div className=\"shrink-0 text-text-tertiary\">{action}</div>}\n </div>\n <div className=\"mt-4 flex flex-1 flex-col\">{children}</div>\n </div>\n ) : (\n children\n )}\n </article>\n );\n});\n","import { FilterX } from \"lucide-react\";\n\n/**\n * The one \"no results\" message, shared across every filtered table/list that\n * can end up empty for the same two reasons -- see the component doc below\n * for why they're deliberately not distinguished.\n */\nexport const NO_RESULTS_TITLE = \"No results match your filters\";\nexport const NO_RESULTS_BODY =\n \"Your filters may be too narrow, conflict with each other, or have no activity in this period.\";\n\n/**\n * The body for the active workspace: named while one is active, since its scope\n * bounds the result as much as the filters do. Under \"All data\" (no name) the\n * generic line stands alone.\n */\nexport function noResultsBody(workspaceName?: string | null): string {\n return workspaceName ? `Nothing in the “${workspaceName}” workspace matches. ${NO_RESULTS_BODY}` : NO_RESULTS_BODY;\n}\n\n/** One caller-supplied recovery action, rendered after the two named handlers. */\nexport interface NoResultsAction {\n label: string;\n onClick: () => void;\n /** Rendered as the filled button; every other action renders as the quiet link/button. */\n primary?: boolean;\n}\n\nexport const PRIMARY_ACTION_CLASS =\n \"rounded-control bg-brand-primaryAction px-3.5 py-2 text-[13px] font-semibold text-white transition-colors hover:opacity-90\";\nexport const QUIET_ACTION_CLASS =\n \"rounded-control text-[13px] font-medium text-text-link transition-colors hover:underline focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\";\n\n/**\n * @pattern NoResultsEmptyState\n * @description Guided empty state for a query that returned nothing.\n * Deliberately one state for two causes, because the user can't tell them\n * apart and the fix is the same either way -- loosen the filters or widen the\n * date range: (1) a filter combination that can't match anything, or (2) a\n * valid combination with no activity in the selected period. So the copy\n * names both possibilities instead of asserting one. Renders as a bare\n * stack -- no border, background, or fixed height -- so it can sit directly\n * in a colSpan table cell (or a card, or a chart body) that already owns\n * that chrome, without imposing its own.\n * @tokens bg-subtle, text-text-tertiary, text-base, text-text-primary,\n * text-text-secondary, rounded-control, bg-brand-primaryAction, text-text-link,\n * focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior The Clear button shows when `onClearFilters` is given AND\n * `hasFilters` isn't explicitly `false` -- so a caller can either pass the\n * handler conditionally (only when there's something to clear) or always\n * pass it and gate visibility with `hasFilters` separately; both existing\n * call patterns work unchanged. The Edit button shows whenever\n * `onEditFilters` is given. `actions` appends further caller-defined\n * recovery buttons (e.g. \"Switch workspace\") after the two named ones, for\n * empty states whose fix isn't about filters at all -- primary gets the\n * filled treatment, everything else the quiet one.\n * @a11y The optional action is a real <button> with visible text as its\n * accessible name; the illustration is aria-hidden. Nothing here announces\n * automatically, so a consumer replacing results should manage its own\n * live region if the change needs announcing.\n * @usage\n * ```tsx\n * <NoResultsEmptyState hasFilters={hasFilters} onClearFilters={clearFilters} onEditFilters={openFilterTray} />\n * <NoResultsEmptyState\n * title=\"Properties not set up in this workspace\"\n * body=\"Switch to a workspace that has them defined or create a new one.\"\n * actions={[{ label: 'Switch workspace', onClick: openSwitcher, primary: true }, { label: 'Create workspace', onClick: createNew }]}\n * />\n * ```\n */\nexport interface NoResultsEmptyStateProps {\n /** @default NO_RESULTS_TITLE */\n title?: string;\n /** Replaces the default body wholesale, workspace name included. */\n body?: string;\n /** The active workspace's name, or nothing under \"All data\". Shapes the default body only -- ignored when `body` is given. */\n workspaceName?: string | null;\n /**\n * Explicit override for whether the Clear button can show. Omit to derive\n * it from whether `onClearFilters` was passed; pass `false` to force it\n * hidden even though a handler was given (e.g. the handler exists but\n * nothing is currently applied).\n */\n hasFilters?: boolean;\n onClearFilters?: () => void;\n onEditFilters?: () => void;\n /** Extra recovery actions, rendered in order after Clear/Edit. */\n actions?: NoResultsAction[];\n /**\n * Optional prefix for `data-testid` attributes on the container\n * (`testIdPrefix` itself), the Clear button (`${testIdPrefix}-clear`), and\n * the Edit button (`${testIdPrefix}-edit`). Omit for no test-id wiring.\n * Pass `\"no-results\"` to reproduce mr-clientapps-insights-studio's current\n * fixed ids (`no-results`, `no-results-clear`, `no-results-edit`) exactly.\n */\n testIdPrefix?: string;\n}\n\nexport function NoResultsEmptyState({\n title = NO_RESULTS_TITLE,\n body,\n workspaceName,\n hasFilters,\n onClearFilters,\n onEditFilters,\n actions,\n testIdPrefix,\n}: NoResultsEmptyStateProps) {\n const bodyText = body ?? noResultsBody(workspaceName);\n const showClear = hasFilters !== false && Boolean(onClearFilters);\n const showEdit = Boolean(onEditFilters);\n const hasActions = showClear || showEdit || Boolean(actions && actions.length > 0);\n\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 text-center\" data-testid={testIdPrefix}>\n <span className=\"flex h-11 w-11 items-center justify-center rounded-full bg-subtle text-text-tertiary\">\n <FilterX size={20} aria-hidden=\"true\" />\n </span>\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n <p className=\"max-w-[420px] text-[13px] leading-relaxed text-text-secondary\">{bodyText}</p>\n {hasActions && (\n <div className=\"mt-1 flex flex-col items-center gap-3\">\n {showClear && (\n <button\n type=\"button\"\n onClick={onClearFilters}\n data-testid={testIdPrefix && `${testIdPrefix}-clear`}\n className={PRIMARY_ACTION_CLASS}\n >\n Clear all filters\n </button>\n )}\n {showEdit && (\n <button\n type=\"button\"\n onClick={onEditFilters}\n data-testid={testIdPrefix && `${testIdPrefix}-edit`}\n className={QUIET_ACTION_CLASS}\n >\n Edit filters\n </button>\n )}\n {actions?.map((action, i) => (\n <button\n key={`${i}-${action.label}`}\n type=\"button\"\n onClick={action.onClick}\n className={action.primary ? PRIMARY_ACTION_CLASS : QUIET_ACTION_CLASS}\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { ChevronDown, X } from \"lucide-react\";\n\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface SummaryGroupItemValue {\n id: string;\n name: string;\n /**\n * Secondary line under the name. Takes a node rather than a plain string\n * so a caller can render something richer than static text there -- e.g.\n * mr-clientapps-insights-studio's Account Lists group swaps this for a\n * \"No accounts assigned -- click here to add accounts\" link when a list is\n * empty, which a plain `string` field couldn't hold.\n */\n meta?: React.ReactNode;\n}\n\nexport interface SummaryGroup {\n id: string;\n label: string;\n items: SummaryGroupItemValue[];\n onRemove: (id: string) => void;\n onRemoveAll: () => void;\n /** Nested sub-sections rendered, indented, beneath this group's own items. */\n subGroups?: SummaryGroup[];\n}\n\n/**\n * @pattern WorkspaceSelectedCard\n * @description Sticky recap card listing what each section's picker has\n * added, as collapsible groups with per-item remove and \"Remove all\" --\n * generic over the `SummaryGroup` shape, no domain coupling. Reconciled from\n * two implementations: insights-studio-prototype's generic `SummaryGroup[]`\n * (kept, since it cleanly covers mr-clientapps-insights-studio's own usage\n * too -- that app's fixed `sets`/`accountLists` prop pair is just this same\n * shape with the group list hardcoded at the call site instead of passed\n * in) and mr-clientapps-insights-studio's `SelectedSummary`, whose\n * `wasEmpty`-ref auto-expand tracking turned out to be the correct one (see\n * `@behavior`) and whose `shadow-1` -- not a real `@mediaradar/design-tokens`\n * class, confirmed against the built theme -- pointed at a real, deliberately\n * omitted elevation this card was missing; the local `shadow-1`/`shadow-2`\n * naming maps to this package's `shadow-raised`/`shadow-overlay` respectively\n * (raised: a static card like this one; overlay: a floating popover/menu),\n * not a 1:1 name swap.\n * @tokens rounded-card, border-border-default, bg-surface, shadow-raised,\n * text-text-secondary, text-text-primary, rounded-full, bg-subtle,\n * rounded-control, bg-canvas, hover:bg-subtle, hover:text-text-danger,\n * text-text-link, divide-border-default\n * @dependencies lucide-react\n * @behavior A group auto-expands only on the empty-to-nonempty transition\n * (including via a nested sub-group's items) and auto-collapses when\n * emptied; manual open/close toggles in between are preserved. This is\n * mr-clientapps-insights-studio's `wasEmpty`-ref logic, not\n * insights-studio-prototype's original `prevCount`-comparison one --\n * verified the two differ: the original re-opened a group on ANY item\n * increase, including one added to an already-open or already\n * manually-collapsed nonempty group, silently undoing the user's own\n * collapse. Sub-groups render indented beneath their parent's own items.\n * @a11y The card's toggle is a button reporting aria-expanded, with an aria-\n * label since it renders icon-only. Decorative marks are aria-hidden.\n * @usage\n * ```tsx\n * <WorkspaceSelectedCard groups={[{ id: 'advertisers', label: 'Advertisers', items: selected, onRemove: removeOne, onRemoveAll: clearAll }]} />\n * ```\n */\nexport interface WorkspaceSelectedCardProps {\n groups: SummaryGroup[];\n /**\n * Optional prefix for `data-testid` attributes on each group's toggle\n * (`${testIdPrefix}-group-<group.id>`) and its \"Remove all\" button\n * (`${testIdPrefix}-remove-all-<group.id>`), applied recursively to\n * sub-groups too. Omit for no test-id wiring.\n *\n * NOTE: this does not reproduce mr-clientapps-insights-studio's current\n * fixed ids byte-for-byte -- its container carries a separate, unrelated\n * `workspace-selected-summary` id (this component has no single container\n * element those groups sit inside, by design, so there's nothing to attach\n * an equivalent id to) while its groups use a *different* prefix,\n * `workspace-summary-group-<type>` / `workspace-summary-remove-all-<type>`.\n * A consumer with existing Playwright locators keyed off those exact\n * strings needs to update them, or the caller needs its own id mapping --\n * not attempted here, same as `DateRangeFilter`'s documented preset-slug\n * mismatch.\n */\n testIdPrefix?: string;\n}\n\nexport function WorkspaceSelectedCard({ groups, testIdPrefix }: WorkspaceSelectedCardProps) {\n return (\n <aside className=\"sticky top-4 flex min-w-0 flex-col gap-4 self-start rounded-card border border-border-default bg-surface px-5 pb-5 pt-4 shadow-raised sm:px-6 sm:pb-6\">\n <div className=\"flex flex-col divide-y divide-border-default\">\n {groups.map((g) => (\n <SummaryGroupItem key={g.id} group={g} testIdPrefix={testIdPrefix} />\n ))}\n </div>\n </aside>\n );\n}\n\nfunction SummaryGroupItem({\n group,\n nested = false,\n testIdPrefix,\n}: {\n group: SummaryGroup;\n nested?: boolean;\n testIdPrefix?: string;\n}) {\n const ownCount = group.items.length;\n const subCount = (group.subGroups ?? []).reduce((n, sg) => n + sg.items.length, 0);\n // Auto-expand tracks own items plus any nested sub-group items, so adding\n // e.g. an account list opens the Advertisers section even with no manual\n // picks in Advertisers itself.\n const expandCount = ownCount + subCount;\n const [open, setOpen] = useState(expandCount > 0);\n // Tracks the empty <-> nonempty transition only -- NOT every count change --\n // so adding another item to a group that's already open, or already\n // manually collapsed while nonempty, never forces its open state either\n // way. Emptying it (via remove / remove-all) does collapse it back down.\n const wasEmpty = useRef(expandCount === 0);\n useEffect(() => {\n if (wasEmpty.current && expandCount > 0) setOpen(true);\n else if (expandCount === 0) setOpen(false);\n wasEmpty.current = expandCount === 0;\n }, [expandCount]);\n\n return (\n <div className={nested ? \"\" : \"py-3 first:pt-0 last:pb-0\"}>\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n aria-expanded={open}\n data-testid={testIdPrefix && `${testIdPrefix}-group-${group.id}`}\n className=\"flex w-full min-w-0 items-center gap-2 text-left\"\n >\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", !open && \"-rotate-90\")}\n />\n <span className={cx(\"truncate font-semibold text-text-primary\", nested ? \"text-[12px]\" : \"text-[13px]\")}>\n {group.label}\n </span>\n <span className=\"shrink-0 rounded-full bg-subtle px-1.5 py-0.5 text-[11px] font-semibold text-text-secondary\">\n {ownCount}\n </span>\n </button>\n {open && (\n <div className=\"pt-2.5\">\n {ownCount === 0 && subCount === 0 ? (\n <p className=\"text-[12px] text-text-secondary\">Nothing selected.</p>\n ) : (\n <div className=\"flex flex-col gap-2.5\">\n {ownCount > 0 && (\n <div className=\"flex flex-col gap-1.5\">\n {group.items.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between gap-2 rounded-control border border-border-default bg-canvas px-2 py-1\"\n >\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[12px] text-text-primary\">{item.name}</span>\n {item.meta && <span className=\"block truncate text-[11px] text-text-secondary\">{item.meta}</span>}\n </span>\n <button\n type=\"button\"\n aria-label={`Remove ${item.name}`}\n onClick={() => group.onRemove(item.id)}\n className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-control text-text-secondary hover:bg-subtle hover:text-text-danger\"\n >\n <X size={12} aria-hidden=\"true\" />\n </button>\n </div>\n ))}\n <button\n type=\"button\"\n onClick={group.onRemoveAll}\n data-testid={testIdPrefix && `${testIdPrefix}-remove-all-${group.id}`}\n className=\"mt-0.5 self-start text-[11px] font-medium text-text-link hover:underline\"\n >\n Remove all\n </button>\n </div>\n )}\n {group.subGroups?.map((sg) => (\n <SummaryGroupItem key={sg.id} group={sg} nested testIdPrefix={testIdPrefix} />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","/**\n * Internal helpers shared by the four chart-placeholder patterns\n * (`BarChartPlaceholder`, `PieChartPlaceholder`, `StackedColumnPlaceholder`,\n * `LineChartPlaceholder`). Not itself a pattern, and not exported from the\n * package entry point -- each of the four owns its own `@pattern` JSDoc and\n * its own variant-specific proportions (bar heights, pie seams, column\n * weights, line series); only the axis/legend scaffolding common to more\n * than one of them lives here.\n */\n\n/** Gridline positions as a percentage down the plot area. */\nexport const GRID_ROWS = [0, 25, 50, 75, 100];\n\n/** Blank y-tick widths -- uneven, the way real tick labels differ in length. */\nexport const Y_TICK_WIDTHS = [26, 30, 30, 26, 20];\n\n/** Gutters, matched to the axis sizes the live charts reserve. */\nexport const Y_AXIS_W = 48;\nexport const X_AXIS_H = 22;\n\n/** Blank legend-label widths, cycled -- real names are not all one length. */\nexport const LEGEND_WIDTHS = [58, 44, 66, 50, 38, 62, 46, 54];\n\n/**\n * Axis scaffolding shared by the placeholders whose live charts have axes:\n * dashed gridlines, plus a blank box at every tick position on both axes.\n * `children` is drawn into the plot area, inset by the axis gutters.\n */\nexport function AxisFrame({\n height,\n xTicks,\n children,\n}: {\n height: number;\n /**\n * Blank x-tick boxes to draw. 0 reserves no gutter -- for a live chart\n * whose x-axis carries no labels of its own.\n */\n xTicks: number;\n children?: React.ReactNode;\n}) {\n const gutter = xTicks > 0 ? X_AXIS_H : 0;\n return (\n <div className=\"w-full\" style={{ height }} role=\"presentation\" aria-hidden=\"true\">\n <div className=\"relative h-full w-full\">\n {/* Plot area */}\n <div className=\"absolute inset-y-0 right-0\" style={{ left: Y_AXIS_W, bottom: gutter }}>\n {GRID_ROWS.map((pct) => (\n <div\n key={pct}\n className=\"absolute inset-x-0 border-t border-dashed\"\n style={{ top: `${pct}%`, borderColor: \"var(--mr-color-border-default)\" }}\n />\n ))}\n <div className=\"absolute inset-0\">{children}</div>\n </div>\n\n {/* Blank y-axis ticks, centered on their gridlines */}\n <div className=\"absolute left-0 top-0\" style={{ width: Y_AXIS_W, bottom: gutter }}>\n {GRID_ROWS.map((pct, i) => (\n <div\n key={pct}\n className=\"absolute right-2 h-2 -translate-y-1/2 rounded-xs bg-subtle\"\n style={{ top: `${pct}%`, width: Y_TICK_WIDTHS[i] }}\n />\n ))}\n </div>\n\n {/* Blank x-axis ticks, one per slot */}\n {xTicks > 0 && (\n <div\n className=\"absolute bottom-0 right-0 flex items-center\"\n style={{ left: Y_AXIS_W, height: X_AXIS_H }}\n >\n {Array.from({ length: xTicks }, (_, i) => (\n <div key={i} className=\"flex flex-1 justify-center\">\n <div className=\"h-2 w-full max-w-[26px] rounded-xs bg-subtle\" />\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Blank legend -- a swatch and a name box per entry, with a value box on the\n * right, holding the column the real legend occupies.\n */\nexport function BlankLegend({ rows, reverse = false }: { rows: number; reverse?: boolean }) {\n return (\n <ul\n className={`flex flex-1 justify-center gap-1.5 ${reverse ? \"flex-col-reverse\" : \"flex-col\"}`}\n role=\"presentation\"\n aria-hidden=\"true\"\n >\n {Array.from({ length: rows }, (_, i) => (\n <li key={i} className=\"flex items-center justify-between gap-2\">\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-xs bg-subtle\" />\n <span\n className=\"h-2 rounded-xs bg-subtle\"\n style={{ width: LEGEND_WIDTHS[i % LEGEND_WIDTHS.length] }}\n />\n </span>\n <span className=\"h-2 w-6 rounded-xs bg-subtle\" />\n </li>\n ))}\n </ul>\n );\n}\n","import { AxisFrame } from \"./chart-placeholder-shared\";\n\n/** Descending bar profile -- the shape a ranked spend chart takes. */\nconst BAR_PROFILE = [92, 86, 76, 65, 57, 40, 30, 24, 18, 13];\n\n/**\n * @pattern BarChartPlaceholder\n * @description Neutral, dataless stand-in for a ranked-bar chart --\n * descending bar profile under a blank-labelled axis frame (dashed\n * gridlines, blank y/x-tick boxes), so an unsatisfiable filter still reads\n * as \"a chart belongs here\" rather than a failed load. No real value ever\n * appears (no channel/league names, media types, dollar amounts,\n * percentages, or series colors), and the shape holds the card's layout\n * steady so nothing jumps when real data arrives.\n * @tokens bg-subtle, border-border-default, rounded-xs\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout, since none of the boxes carry real\n * content for assistive tech to announce. The bar count and profile are a\n * fixed shape, not driven by `height`.\n * @a11y role=\"presentation\" with aria-hidden marks: a visual stand-in with no\n * data, deliberately invisible to assistive tech. Don't add a caption\n * expecting it to be announced.\n * @usage\n * ```tsx\n * <BarChartPlaceholder />\n * <BarChartPlaceholder height={180} />\n * ```\n */\nexport interface BarChartPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n}\n\nexport function BarChartPlaceholder({ height = 220 }: BarChartPlaceholderProps) {\n return (\n <AxisFrame height={height} xTicks={BAR_PROFILE.length}>\n <div className=\"flex h-full w-full items-end gap-2\">\n {BAR_PROFILE.map((pct, i) => (\n <div key={i} className=\"flex-1 rounded-t-[3px] bg-subtle\" style={{ height: `${pct}%` }} />\n ))}\n </div>\n </AxisFrame>\n );\n}\n","import { AxisFrame } from \"./chart-placeholder-shared\";\n\n/**\n * Four trend paths as y-percentages down the plot (so a lower number sits\n * higher on the chart), sampled at ten evenly spaced x positions. Four\n * rather than a higher real series count: enough to read as a multi-series\n * trend, few enough that same-colored paths don't turn to mush.\n */\nconst LINE_SERIES = [\n [58, 52, 55, 41, 45, 33, 36, 25, 28, 17],\n [74, 71, 66, 68, 59, 61, 54, 56, 48, 45],\n [40, 44, 37, 41, 34, 38, 31, 34, 27, 26],\n [86, 82, 84, 77, 79, 71, 73, 66, 68, 61],\n];\n\n/** Index at which the solid line hands off to the dashed forecast tail. */\nconst LINE_FORECAST_FROM = 7;\n\n/**\n * @pattern LineChartPlaceholder\n * @description Neutral, dataless stand-in for a multi-series trend chart --\n * four grey paths over the shared axis frame, each with a solid-then-dashed\n * handoff for the live chart's forecast tail, and a point at every sample.\n * Points are positioned rather than drawn in the SVG: the plot stretches to\n * the card, and a stretched `<circle>` would go oval. Same no-results use\n * as `BarChartPlaceholder` -- no real value ever appears, and the shape\n * holds the card's layout steady so nothing jumps when real data arrives.\n * Paths and points share the `bg-subtle` fill of the axis labels, so the\n * whole placeholder reads as one tint, the way the bars do.\n * @tokens bg-subtle, border-border-default, rounded-xs\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout (inherited from `AxisFrame`). The series\n * count and shapes are fixed; `height` is the only variable.\n * @a11y role=\"presentation\" with aria-hidden marks: a visual stand-in with no\n * data, deliberately invisible to assistive tech. Don't add a caption\n * expecting it to be announced.\n * @usage\n * ```tsx\n * <LineChartPlaceholder />\n * <LineChartPlaceholder height={200} />\n * ```\n */\nexport interface LineChartPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n}\n\nexport function LineChartPlaceholder({ height = 280 }: LineChartPlaceholderProps) {\n const toPath = (pts: number[], from: number, to: number) =>\n pts\n .slice(from, to)\n .map((y, i) => `${((i + from) / (pts.length - 1)) * 100},${y}`)\n .join(\" \");\n\n return (\n <AxisFrame height={height} xTicks={LINE_SERIES[0].length}>\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" className=\"absolute inset-0 h-full w-full\">\n {LINE_SERIES.map((pts, s) => (\n <g key={s}>\n <polyline\n points={toPath(pts, 0, LINE_FORECAST_FROM + 1)}\n fill=\"none\"\n stroke=\"var(--mr-color-subtle)\"\n strokeWidth=\"2\"\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <polyline\n points={toPath(pts, LINE_FORECAST_FROM, pts.length)}\n fill=\"none\"\n stroke=\"var(--mr-color-subtle)\"\n strokeWidth=\"2\"\n strokeDasharray=\"5 4\"\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n ))}\n </svg>\n {LINE_SERIES.map((pts, s) =>\n pts.map((y, i) => (\n <div\n key={`${s}-${i}`}\n className=\"absolute h-1.5 w-1.5 -translate-x-1/2 -translate-y-1/2 rounded-full\"\n style={{\n left: `${(i / (pts.length - 1)) * 100}%`,\n top: `${y}%`,\n backgroundColor: \"var(--mr-color-subtle)\",\n }}\n />\n ))\n )}\n </AxisFrame>\n );\n}\n","import { BlankLegend } from \"./chart-placeholder-shared\";\n\n/** Uneven seam angles (degrees, clockwise from 12 o'clock) -- a share split. */\nconst PIE_SEAMS = [0, 115, 180, 230, 262, 288, 310, 332];\n\n/**\n * @pattern PieChartPlaceholder\n * @description Neutral, dataless stand-in for a pie chart -- a grey disc\n * seamed where slices would fall, beside a blank legend. No axis, matching\n * the live pie it stands in for. Same no-results use as\n * `BarChartPlaceholder`: an unsatisfiable filter reads as \"a chart belongs\n * here\" rather than a failed load, with no real value (names, media types,\n * dollar amounts, percentages, series colors) ever appearing.\n * @tokens bg-subtle, bg-surface, rounded-xs\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout. `legendRows` controls the blank legend\n * only; the disc's seam count is a fixed shape. Seams are cut in the\n * card's `bg-surface` color, as `StackedColumnPlaceholder`'s bands are.\n * @a11y role=\"presentation\" with aria-hidden marks: it is a visual stand-in with\n * no data, deliberately invisible to assistive tech. Don't add a caption\n * expecting it to be announced.\n * @usage\n * ```tsx\n * <PieChartPlaceholder />\n * <PieChartPlaceholder legendRows={4} />\n * ```\n */\nexport interface PieChartPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n /** Number of blank legend rows to render beside the disc. */\n legendRows?: number;\n}\n\nexport function PieChartPlaceholder({ height = 220, legendRows = 8 }: PieChartPlaceholderProps) {\n const r = 45;\n return (\n <div className=\"flex w-full items-center gap-3\" style={{ height }} role=\"presentation\" aria-hidden=\"true\">\n <div className=\"flex h-full items-center justify-center\" style={{ width: \"60%\" }}>\n <svg viewBox=\"0 0 100 100\" className=\"h-full\" style={{ aspectRatio: \"1 / 1\" }}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"var(--mr-color-subtle)\" />\n {PIE_SEAMS.map((deg) => {\n const rad = ((deg - 90) * Math.PI) / 180;\n return (\n <line\n key={deg}\n x1=\"50\"\n y1=\"50\"\n x2={50 + r * Math.cos(rad)}\n y2={50 + r * Math.sin(rad)}\n stroke=\"var(--mr-color-surface)\"\n strokeWidth=\"1\"\n />\n );\n })}\n </svg>\n </div>\n <BlankLegend rows={legendRows} />\n </div>\n );\n}\n","import { AxisFrame, BlankLegend } from \"./chart-placeholder-shared\";\n\n/**\n * Relative band weights for a 100% stacked column, top to bottom. Sliced to\n * one per legend entry and normalized, so the column carries exactly the\n * segments the legend beside it lists -- the way the live chart does.\n */\nconst COLUMN_WEIGHTS = [20, 30, 15, 35, 24, 12, 28, 18];\n\nfunction columnBands(count: number) {\n const weights = Array.from({ length: count }, (_, i) => COLUMN_WEIGHTS[i % COLUMN_WEIGHTS.length]);\n const total = weights.reduce((a, b) => a + b, 0);\n return weights.map((w) => (w / total) * 100);\n}\n\n/**\n * @pattern StackedColumnPlaceholder\n * @description Neutral, dataless stand-in for a 100% stacked column -- a\n * single banded column beside a blank legend. `axis` follows the live card\n * it stands in for: a share-of-total chart plotting on a 0-100% axis passes\n * `axis`, a bare stack with no scale (e.g. a share-of-voice column) omits\n * it. Same no-results use as `BarChartPlaceholder` -- no real value ever\n * appears, and the shape holds the card's layout steady.\n * @tokens bg-subtle, bg-surface, border-border-default, rounded-control\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout. Band seams are 1px gaps in the card's\n * `bg-surface` color rather than a border tone: a `border-border-default`\n * seam disappears on the `bg-subtle` fill, and `border-border-strong` reads\n * darker than the rest of the placeholder. Legend rows are reversed (bottom-up) when `axis`\n * is off, matching a bare stack's usual bottom-anchored reading order.\n * @a11y role=\"presentation\" with aria-hidden marks: a visual stand-in with no\n * data, deliberately invisible to assistive tech.\n * @usage\n * ```tsx\n * <StackedColumnPlaceholder />\n * <StackedColumnPlaceholder axis />\n * ```\n */\nexport interface StackedColumnPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n /** Column width in pixels. */\n width?: number;\n /** Number of bands (and matching blank legend rows). */\n legendRows?: number;\n /** Wrap the column in a 0-100% axis frame, matching a live share-of-total chart. */\n axis?: boolean;\n}\n\nexport function StackedColumnPlaceholder({\n height = 220,\n width = 96,\n legendRows = 4,\n axis = false,\n}: StackedColumnPlaceholderProps) {\n const column = (\n <div className=\"flex h-full flex-col overflow-hidden rounded-control bg-subtle\" style={{ width }}>\n {columnBands(legendRows).map((pct, i) => (\n <div\n key={i}\n style={{\n height: `${pct}%`,\n /* A gap in the card's color, not a border tone: border-default\n disappears on the subtle fill, border-strong reads darker. */\n borderTop: i === 0 ? undefined : \"1px solid var(--mr-color-surface)\",\n }}\n />\n ))}\n </div>\n );\n return (\n <div className=\"flex w-full gap-4\" style={{ height }} role=\"presentation\" aria-hidden=\"true\">\n {axis ? (\n <div style={{ width: \"55%\" }}>\n <AxisFrame height={height} xTicks={0}>\n <div className=\"flex h-full items-stretch justify-center\">{column}</div>\n </AxisFrame>\n </div>\n ) : (\n <div className=\"flex items-stretch py-1\">{column}</div>\n )}\n <BlankLegend rows={legendRows} reverse={!axis} />\n </div>\n );\n}\n","\"use client\";\n\nimport { useEffect, useId, useLayoutEffect, useRef, useState, type ReactNode, type RefObject, type TransitionEvent } from \"react\";\nimport { createPortal } from \"react-dom\";\n\n/** Joins truthy class fragments -- a local stand-in so this package doesn't\n * pull in a classnames dependency for one conditional class. */\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/** The bubble's real opacity-transition length in ms, read from its computed\n * style rather than hard-coded, so the unmount fallback timer can never\n * disagree with the `--mr-motion-duration-interactive` token. 0 when there is\n * no transition to wait for: reduced motion (the OS setting, or the\n * `motion-reduce:transition-none` class it drives), or a consumer whose\n * design-tokens doesn't define the variable -- an unresolved `var()` there\n * computes to 0s, so it degrades to the old instant hide rather than\n * stranding the bubble. */\nfunction exitDurationMs(el: HTMLElement): number {\n if (typeof window.matchMedia === \"function\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return 0;\n const cs = window.getComputedStyle(el);\n if (cs.transitionProperty === \"none\") return 0;\n const toMs = (v: string) => {\n const n = parseFloat(v);\n if (!Number.isFinite(n)) return 0;\n return v.trim().endsWith(\"ms\") ? n : n * 1000;\n };\n const durations = cs.transitionDuration.split(\",\").map(toMs);\n const delays = cs.transitionDelay.split(\",\").map(toMs);\n return Math.max(0, ...durations.map((d, i) => d + (delays[i] ?? delays[0] ?? 0)));\n}\n\n/**\n * @pattern Tooltip\n * @description Portalled hover/focus tooltip. Two ways to attach a trigger:\n * wrap `children` (the default -- an inline trigger, e.g. a truncated table\n * cell or a chart legend entry), or pass `anchorRef` for an element that\n * already needs its own ref, or where wrapping in an extra inline box would\n * disturb layout (an icon-only collapsed nav rail, for example) -- the two\n * are mutually exclusive ways of specifying the trigger, and `children` is\n * ignored when `anchorRef` is set. Positioned `fixed` from the trigger's\n * bounding rect and rendered through a portal to `document.body`, so it\n * escapes both `overflow` clipping inside scrollable panels and the broken\n * `fixed` containing block a transformed ancestor creates.\n * @tokens rounded-control, border-border-default, bg-surface, shadow-overlay,\n * text-text-primary, bg-text-primary, text-surface,\n * duration-(--mr-motion-duration-interactive)\n * @variant surface - Default. Themed surface/border bubble -- matches the\n * Recharts chart tooltips this was originally built for.\n * @variant inverted - Solid dark pill (no border) -- for a tooltip sitting\n * over a nav rail or other icon-only surface, where the themed surface bubble\n * doesn't read as clearly against a busy background.\n * @behavior Shows on hover and on keyboard focus (so it stays reachable\n * without a pointer) after `delay` ms (0 = immediate, the default). Fades in\n * and out (opacity, `ease-in-out`, over the sys\n * `--mr-motion-duration-interactive` token -- 200ms today); the bubble stays\n * mounted through the fade-out and is removed from the DOM once it ends.\n * Under `prefers-reduced-motion: reduce` there is no fade: it appears and is\n * removed instantly. The hide starts on mouseleave/blur, cancelling a pending\n * delayed show if it hasn't fired yet -- except in `interactive` mode, which\n * delays the hide briefly so the pointer can travel from the trigger into the\n * tooltip's own content. Re-hovering (or re-focusing) the trigger while the\n * bubble is still fading out reverses the fade from where it is, without\n * waiting out `delay` again, since it is already on screen; so does moving\n * the pointer back into an `interactive` bubble. A non-interactive bubble is\n * `pointer-events-none` throughout, fade-out included, so it never\n * intercepts clicks meant for what sits under it. Pass `whenTruncated` to\n * only surface it once the trigger's content\n * is actually clipped by ellipsis (`scrollWidth > clientWidth`). `placement`\n * 'top'/'bottom' centre (or `align=\"start\"` left-align) on the trigger;\n * 'right' centres vertically beside the anchor and 'bottom-end' hangs below,\n * right-aligned to the anchor's right edge -- both meant for `anchorRef`\n * anchors near the viewport's right edge, where a centred box would run\n * off-screen or read awkwardly beside a narrow icon.\n * @a11y Renders role=\"tooltip\" and is wired to its anchor by aria-describedby,\n * so the anchor must exist and keep a stable id. It describes rather than\n * labels: it is announced in addition to the anchor's own name, not\n * instead of it, so never put the only label for a control in here.\n * @usage\n * ```tsx\n * <Tooltip label=\"Full advertiser name\" whenTruncated>\n * <span className=\"truncate\">{name}</span>\n * </Tooltip>\n *\n * const ref = useRef<HTMLButtonElement>(null);\n * <button ref={ref}>Sports</button>\n * <Tooltip label=\"Sports\" anchorRef={ref} placement=\"right\" delay={500} variant=\"inverted\" />\n * ```\n */\nexport interface TooltipProps {\n /** Tooltip content shown on hover/focus. */\n label: ReactNode;\n /** The trigger content, wrapped inline. Omit when using `anchorRef`. */\n children?: ReactNode;\n /**\n * Attach to an existing element instead of wrapping `children` in a\n * trigger span -- see the pattern description. When set, `children` /\n * `className` / `whenTruncated` all still apply to that element (its\n * `scrollWidth`/`clientWidth` drive `whenTruncated`), just without this\n * component rendering a wrapping element of its own.\n */\n anchorRef?: RefObject<HTMLElement | null>;\n /** Classes for the inline trigger wrapper (e.g. `truncate`, `min-w-0`). Ignored with `anchorRef`. */\n className?: string;\n /**\n * Only reveal the tooltip when the trigger's content is actually clipped by\n * ellipsis (`scrollWidth > clientWidth`). Off by default -- the tooltip always\n * shows.\n */\n whenTruncated?: boolean;\n /**\n * When true, the tooltip accepts pointer events so it can contain links and\n * other interactive content.\n */\n interactive?: boolean;\n /**\n * Which side of the trigger to render on. 'top' (default) / 'bottom'\n * centre on the trigger (or left-align with `align=\"start\"`). 'right' /\n * 'bottom-end' are for an `anchorRef` anchor -- see the pattern description.\n */\n placement?: \"top\" | \"bottom\" | \"right\" | \"bottom-end\";\n /**\n * How the box lines up with the trigger horizontally, for 'top'/'bottom'\n * placement only. \"center\" (the default) centres it; \"start\" puts its left\n * edge on the trigger so it grows rightward, which reads better for a small\n * icon sitting beside the text it describes -- a centred box there hangs\n * out over the content to the left.\n */\n align?: \"center\" | \"start\";\n /**\n * Hover delay in ms before the tooltip appears. 0 (default) shows\n * immediately. A collapsed nav rail passes 500 so a fast mouse pass over\n * several icons doesn't flash a tooltip per icon.\n */\n delay?: number;\n /** 'surface' (default) or 'inverted' -- see the pattern description. */\n variant?: \"surface\" | \"inverted\";\n /** Optional prefix for a `data-testid` on the floating tooltip bubble. */\n testIdPrefix?: string;\n}\n\nexport function Tooltip({\n label,\n children,\n anchorRef,\n className,\n whenTruncated = false,\n interactive = false,\n placement = \"top\",\n align = \"center\",\n delay = 0,\n variant = \"surface\",\n testIdPrefix,\n}: TooltipProps) {\n const [anchor, setAnchor] = useState<{ top: number; left: number; width: number; height: number; bottom: number; right: number } | null>(null);\n // The floating box's actual rendered width, measured post-mount. `null` until then --\n // that's what keeps the box hidden for a frame instead of flashing at a guessed\n // position (see the layout effect below).\n const [boxWidth, setBoxWidth] = useState<number | null>(null);\n const ref = useRef<HTMLSpanElement>(null);\n const boxRef = useRef<HTMLSpanElement>(null);\n const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const showTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n // Fallback for the exit fade: unmounts the bubble if `transitionend` never\n // arrives (a transition interrupted by a style change, or a hidden tab).\n const exitTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n // `shown` drives the opacity class; `anchor != null` is \"mounted\". They\n // differ during a fade: mounted but not shown while fading out, and for the\n // frame before a fresh box is measured. The refs mirror intent and mount\n // for the handlers, which in `anchorRef` mode are attached once and would\n // otherwise read stale state.\n const [shown, setShown] = useState(false);\n const openRef = useRef(false);\n const mountedRef = useRef(false);\n const id = useId();\n\n const clearHideTimer = () => {\n if (hideTimer.current) {\n clearTimeout(hideTimer.current);\n hideTimer.current = null;\n }\n };\n const clearShowTimer = () => {\n if (showTimer.current) {\n clearTimeout(showTimer.current);\n showTimer.current = null;\n }\n };\n const clearExitTimer = () => {\n if (exitTimer.current) {\n clearTimeout(exitTimer.current);\n exitTimer.current = null;\n }\n };\n\n useEffect(\n () => () => {\n clearHideTimer();\n clearShowTimer();\n clearExitTimer();\n },\n []\n );\n\n const reveal = () => {\n const el = anchorRef ? anchorRef.current : ref.current;\n if (!el) return;\n if (whenTruncated && el.scrollWidth <= el.clientWidth) return;\n clearExitTimer();\n openRef.current = true;\n const r = el.getBoundingClientRect();\n // A fresh mount stays hidden until measured (see the layout effect). One\n // still fading out keeps its measured width, so reviving it never\n // flashes it hidden.\n if (!mountedRef.current) setBoxWidth(null);\n mountedRef.current = true;\n // A new object every time, so the layout effect re-runs and flips `shown`.\n setAnchor({ top: r.top, left: r.left, width: r.width, height: r.height, bottom: r.bottom, right: r.right });\n if (anchorRef) el.setAttribute(\"aria-describedby\", id);\n };\n\n const show = () => {\n clearHideTimer();\n clearShowTimer();\n // Already on screen (mid fade-out): reverse it now rather than making the\n // user wait out `delay` for something they can already see.\n if (delay > 0 && !mountedRef.current) {\n showTimer.current = setTimeout(reveal, delay);\n } else {\n reveal();\n }\n };\n\n // End of the exit fade: actually remove the bubble. A no-op if a re-hover\n // revived it in the meantime.\n const unmount = () => {\n clearExitTimer();\n if (openRef.current || !mountedRef.current) return;\n mountedRef.current = false;\n setAnchor(null);\n setBoxWidth(null);\n if (anchorRef?.current) anchorRef.current.removeAttribute(\"aria-describedby\");\n };\n\n // Starts the exit fade. The bubble stays mounted until its opacity\n // transition ends (onTransitionEnd below), with a timer as a fallback.\n const hideNow = () => {\n clearShowTimer();\n clearHideTimer();\n openRef.current = false;\n if (!mountedRef.current) return;\n setShown(false);\n clearExitTimer();\n const ms = boxRef.current ? exitDurationMs(boxRef.current) : 0;\n if (ms === 0) {\n unmount();\n return;\n }\n exitTimer.current = setTimeout(unmount, ms + 50);\n };\n\n // Pointer entered an interactive bubble: cancel a pending hide, and revive\n // it if it had already started fading out.\n const keepOpen = () => {\n clearHideTimer();\n if (openRef.current || !mountedRef.current) return;\n clearExitTimer();\n openRef.current = true;\n setShown(true);\n };\n\n const onBoxTransitionEnd = (e: TransitionEvent<HTMLSpanElement>) => {\n if (e.target !== e.currentTarget || e.propertyName !== \"opacity\") return;\n if (!openRef.current) unmount();\n };\n\n // The floating label lives in a portal (separate DOM subtree), so for interactive\n // tooltips leaving the trigger would hide it before the pointer reaches the content.\n // Delay the hide so the pointer can travel across the gap; the content cancels it.\n const hide = () => {\n clearShowTimer();\n if (!interactive) {\n hideNow();\n return;\n }\n clearHideTimer();\n hideTimer.current = setTimeout(hideNow, 120);\n };\n\n // anchorRef mode: this component renders no trigger element of its own, so\n // the show/hide handlers attach directly to the caller's element instead of\n // JSX event props. Also wires keyboard focus, which the original NavTooltip\n // (mouse-only addEventListener) didn't -- kept reachable without a pointer,\n // matching every other hover-trigger component in this package.\n useEffect(() => {\n if (!anchorRef) return;\n const el = anchorRef.current;\n if (!el) return;\n el.addEventListener(\"mouseenter\", show);\n el.addEventListener(\"mouseleave\", hide);\n el.addEventListener(\"focus\", show);\n el.addEventListener(\"blur\", hide);\n return () => {\n el.removeEventListener(\"mouseenter\", show);\n el.removeEventListener(\"mouseleave\", hide);\n el.removeEventListener(\"focus\", show);\n el.removeEventListener(\"blur\", hide);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [anchorRef, placement, delay]);\n\n // Measured once the box mounts at its natural size, so the horizontal clamp below\n // reflects real content width rather than the max-w-xs (320px) ceiling.\n // Measuring also forces a style recalc with a fresh box at opacity-0, so\n // flipping `shown` right after starts a real fade-in instead of the box\n // appearing at full opacity on its first paint.\n useLayoutEffect(() => {\n if (!anchor) return;\n const el = boxRef.current;\n if (!el) return;\n setBoxWidth(el.getBoundingClientRect().width);\n if (openRef.current) setShown(true);\n }, [anchor, label]);\n\n const margin = 8;\n let style: { top: number; left?: number; right?: number } = { top: 0, left: 0 };\n let translate = \"\";\n if (anchor) {\n if (placement === \"right\") {\n style = { top: anchor.top + anchor.height / 2, left: anchor.right + 8 };\n translate = \"-translate-y-1/2\";\n } else if (placement === \"bottom-end\") {\n style = { top: anchor.bottom + 8, right: window.innerWidth - anchor.right };\n } else {\n const w = boxWidth ?? anchor.width;\n const desired = align === \"start\" ? anchor.left : anchor.left + anchor.width / 2 - w / 2;\n const left = Math.min(Math.max(desired, margin), Math.max(margin, window.innerWidth - w - margin));\n style = { left, top: placement === \"bottom\" ? anchor.bottom : anchor.top };\n translate = placement === \"bottom\" ? \"translate-y-2\" : \"-translate-y-[calc(100%+8px)]\";\n }\n }\n\n const floating =\n anchor != null && typeof document !== \"undefined\"\n ? createPortal(\n <span\n ref={boxRef}\n role=\"tooltip\"\n id={id}\n data-testid={testIdPrefix && `${testIdPrefix}-tooltip`}\n style={{ top: style.top, left: style.left, right: style.right, visibility: boxWidth == null ? \"hidden\" : \"visible\" }}\n onMouseEnter={interactive ? keepOpen : undefined}\n onMouseLeave={interactive ? hide : undefined}\n onTransitionEnd={onBoxTransitionEnd}\n // z-[90]: deliberately an arbitrary value, not @mediaradar/design-\n // tokens' semantic z-tooltip (1200) -- same reasoning as InfoTip's:\n // this portals to document.body, becoming a sibling of any open\n // dialog rather than a child of it, and the real z-index scale a\n // consuming app uses for its own modals/toasts can't be assumed\n // from here. 90 sits above a z-[80] modal/menu layer and below a\n // z-[100] toast layer, confirmed against mr-clientapps' own scale\n // (see InfoTip). Also replaces this component's own two source\n // z-index values -- Tooltip.tsx already used this same z-[90];\n // NavTooltip's z-60 had no such documented reasoning behind it.\n className={cx(\n \"fixed z-[90] w-max max-w-xs whitespace-normal break-words px-2.5 py-1.5 text-xs leading-snug\",\n // Fade in/out. The sys duration token rather than a ref one:\n // it is what Button's hover/press transition uses, and a\n // tooltip's fade is the same kind of interactive feedback.\n // design-tokens has no in-out curve (ease-interactive is the\n // decelerating \"standard\" curve), so ease-in-out is Tailwind's.\n \"transition-opacity duration-(--mr-motion-duration-interactive) ease-in-out motion-reduce:transition-none\",\n shown ? \"opacity-100\" : \"opacity-0\",\n // Non-interactive: never a pointer target, fade-out included.\n interactive ? \"pointer-events-auto\" : \"pointer-events-none\",\n variant === \"inverted\" ? \"rounded-control bg-text-primary text-surface\" : \"rounded-control border border-border-default bg-surface text-text-primary shadow-overlay\",\n translate\n )}\n >\n {label}\n </span>,\n document.body\n )\n : null;\n\n if (anchorRef) return floating;\n\n return (\n <span\n ref={ref}\n className={className}\n onMouseEnter={show}\n onMouseLeave={hide}\n onFocus={show}\n onBlur={hide}\n aria-describedby={anchor ? id : undefined}\n >\n {children}\n {floating}\n </span>\n );\n}\n","/**\n * @pattern AdvertiserNoResults\n * @description Shown when a search-first picker's search returns nothing --\n * gives an actionable next step rather than just a bare \"no results\"\n * message. Named for its original (and still primary) use across\n * `insights-studio-prototype`'s three advertiser-search filter trays\n * (Creative Intel, Publisher, Sports), but the `hint` prop makes it reusable\n * for any other search-first dimension. Distinct from the more general\n * `NoResultsEmptyState` (a whole-board \"no results match your filters\"\n * state) -- this one is scoped to a single search box returning nothing,\n * inline within a picker's option list.\n * @tokens text-text-primary, text-text-tertiary\n * @usage\n * ```tsx\n * <AdvertiserNoResults query={query} />\n * <AdvertiserNoResults query={query} hint=\"Try a different spelling, or switch the Agency Type.\" />\n * ```\n */\nexport interface AdvertiserNoResultsProps {\n /** The search term that returned nothing. */\n query: string;\n /** The actionable next step under the message. */\n hint?: string;\n}\n\nexport function AdvertiserNoResults({\n query,\n hint = \"Try checking your spelling or searching for a broader brand name.\",\n}: AdvertiserNoResultsProps) {\n return (\n <div className=\"flex flex-col items-center gap-1.5 px-4 py-8 text-center\">\n <p className=\"text-[13px] font-medium text-text-primary\">No results found for &ldquo;{query}&rdquo;</p>\n <p className=\"text-[12px] leading-snug text-text-tertiary\">{hint}</p>\n </div>\n );\n}\n","import { ListChecks } from \"lucide-react\";\n\n/**\n * @pattern SelectAllVisible\n * @description \"Select all visible\" row for a search-first picker's result\n * list -- only render it once the caller decides the visible result set is\n * long enough to warrant it (`insights-studio-prototype`'s three advertiser-\n * search filter trays all gate it behind a 5-result threshold; mr-clientapps'\n * `ScopedSearchSection` uses the identical threshold and copy for its own\n * scoped search sections). Communicates how many are visible and toggles\n * between \"Select all\" and \"Deselect\" based on `allSelected`.\n * @tokens rounded-control, text-text-link, hover:bg-subtle\n * @dependencies lucide-react\n * @a11y A plain <button>, not a checkbox -- it performs a bulk action rather\n * than holding a checked state, so it deliberately carries no\n * role=\"checkbox\" or aria-checked. Its icon is aria-hidden and the visible\n * text is the accessible name.\n * @usage\n * ```tsx\n * {results.length > 5 && (\n * <SelectAllVisible count={results.length} allSelected={allSelected} onToggle={toggleAll} />\n * )}\n * ```\n */\nexport interface SelectAllVisibleProps {\n /** Number of currently visible results. */\n count: number;\n /** Whether every visible result is already selected. */\n allSelected: boolean;\n onToggle: () => void;\n /** Optional prefix for a `data-testid` on the row. */\n testIdPrefix?: string;\n}\n\nexport function SelectAllVisible({ count, allSelected, onToggle, testIdPrefix }: SelectAllVisibleProps) {\n return (\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-select-all-visible`}\n onClick={onToggle}\n className=\"flex w-full items-center gap-2 rounded-control px-2 py-1.5 text-left text-[12px] font-semibold text-text-link transition-colors hover:bg-subtle\"\n >\n <ListChecks size={14} aria-hidden=\"true\" />\n {allSelected ? `Deselect ${count} visible` : `Select all ${count} visible`}\n </button>\n );\n}\n","import { ChevronDown } from \"lucide-react\";\n\n/** Joins truthy class fragments -- a local stand-in so this package doesn't\n * pull in a classnames dependency for one conditional class. */\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/**\n * @pattern SelectedSection\n * @description Collapsible \"Selected (n)\" container for a search-first\n * picker. Selections can pile up and crowd out the live search results, so\n * the user can fold them away to refocus on the search. Controlled so the\n * parent can auto-collapse it (e.g. when the search is cleared, or jointly\n * with a sibling \"parked\" section) -- `insights-studio-prototype`'s three\n * advertiser-search filter trays all drive `open` this way. The caller\n * renders each selected row itself as `children` rather than this component\n * owning row markup: the three real call sites render genuinely different\n * row content (plain rows, opacity-dimmed \"parked\" rows, per-tray custom\n * columns), so a fixed row shape would have forced a compromise none of them\n * need. Self-hides at `count === 0` so a caller can render it unconditionally.\n * @tokens rounded-control, text-text-tertiary, hover:text-text-primary\n * @dependencies lucide-react\n * @a11y The disclosure header is a button reporting aria-expanded, and the\n * chevron is aria-hidden. It is a disclosure, not a selection control --\n * the rows inside own their own semantics.\n * @usage\n * ```tsx\n * <SelectedSection count={selected.length} open={open} onToggle={() => setOpen((o) => !o)}>\n * {selected.map((s) => <Row key={s.id} item={s} />)}\n * </SelectedSection>\n * ```\n */\nexport interface SelectedSectionProps {\n count: number;\n open: boolean;\n onToggle: () => void;\n /** The caller renders each selected row itself. */\n children: React.ReactNode;\n /** Optional prefix for a `data-testid` on the toggle button. */\n testIdPrefix?: string;\n}\n\nexport function SelectedSection({ count, open, onToggle, children, testIdPrefix }: SelectedSectionProps) {\n if (count === 0) return null;\n return (\n <div className=\"flex flex-col\">\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-selected-toggle`}\n onClick={onToggle}\n aria-expanded={open}\n className=\"flex w-full items-center gap-1.5 rounded-control px-2 py-1 text-left text-[11px] font-semibold uppercase tracking-wide text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <ChevronDown size={13} aria-hidden=\"true\" className={cx(\"transition-transform\", !open && \"-rotate-90\")} />\n Selected ({count})\n </button>\n {open && <div className=\"flex flex-col gap-0.5\">{children}</div>}\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Search, Plus, Info, ChevronRight, ChevronDown, Check, List, Loader2 } from \"lucide-react\";\nimport { CheckBox } from \"./CheckBox\";\n\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens, trims edge hyphens -- used for data-testid slugs. */\nfunction slug(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/(^-|-$)/g, \"\");\n}\n\nexport interface PickerRow {\n id: string;\n name: string;\n children?: PickerRow[];\n}\n\nexport interface PickerColumn<T extends PickerRow> {\n key: string;\n header: string;\n render: (row: T) => ReactNode;\n className?: string;\n}\n\nexport interface PickerFilter<T extends PickerRow> {\n label: string;\n options: string[];\n /** Returns the row's value for this filter (matched against options). */\n value: (row: T) => string | undefined;\n}\n\n/** The subset of an account-list record this component actually renders in\n * its \"Account lists\" tab -- a caller's own richer type (with members,\n * createdBy, etc.) is passed in as-is; only these fields are read. */\nexport interface SelectionPickerAccountList {\n id: string;\n name: string;\n /** Number of accounts currently in the list. */\n count: number;\n /** Entity types represented in the list, for a quick descriptive line. */\n entityTypes: string[];\n updatedAt: string;\n}\n\nexport interface SelectionPickerProps<T extends PickerRow> {\n /** Full catalog to search/filter over client-side. Ignored when `results`\n * is given instead -- that's the async/paginated mode, see `results`. */\n catalog?: T[];\n selected: T[];\n onChange: (next: T[]) => void;\n columns: PickerColumn<T>[];\n /** First filter is rendered as the primary entity-type group. */\n filters: PickerFilter<T>[];\n searchPlaceholder?: string;\n /** Optional mock drill-down: returns child rows to reveal under a row. */\n getChildren?: (row: T) => T[] | undefined;\n helper?: string;\n /** Trailing Info/drill-down column. Defaults to shown. */\n showInfoColumn?: boolean;\n /** Filter options pre-selected on mount, keyed by filter label. */\n defaultFilters?: Record<string, string[]>;\n /** When true, results appear only once the user types a query -- active\n * filters alone don't reveal the table (used where a filter is pre-selected). */\n requireQuery?: boolean;\n /** When true, the full catalog shows immediately without a search -- for\n * short, browsable lists (e.g. US states). */\n showResultsWithoutSearch?: boolean;\n /** When provided, a \"Search / Account lists\" source toggle appears and the\n * Account lists tab lets the user pull in whole uploaded lists. */\n accountLists?: SelectionPickerAccountList[];\n selectedListIds?: string[];\n onToggleList?: (id: string) => void;\n /** Rows that are already committed elsewhere and can't be toggled here --\n * they render dimmed with no checkbox at all (an \"Add\" picker shouldn't\n * offer to un-add something it isn't responsible for). Select-all skips\n * them, so it can't strip them out from under the caller. */\n lockedIds?: ReadonlySet<string>;\n /**\n * Externally-computed, already-filtered rows -- for a caller whose search\n * is server-side/async (loading, pagination) instead of a full in-memory\n * `catalog` filtered client-side. When given, this replaces `catalog`'s\n * own search/filter matching entirely: the component renders exactly\n * these rows, still gated by the same \"has the user searched or filtered\n * yet\" reveal rule as catalog mode. Pair with `onQueryChange` so the\n * caller knows what to search for, and with\n * `loading`/`error`/`hasMore`/`onLoadMore` for the rest of a typical async\n * search's states. Omit (the default) to keep the original catalog +\n * client-side search/filter behavior -- an existing caller's behavior\n * never changes just by picking up a new version of this component.\n */\n results?: T[];\n /** Fires on every keystroke in the search box with the new query text --\n * for a caller in `results` mode that needs to know what to search for.\n * Fire-and-forget; this component still owns the input's value either way. */\n onQueryChange?: (query: string) => void;\n /** Shows a centered spinner in place of rows. Only meaningful in `results` mode. */\n loading?: boolean;\n /** Shows a \"couldn't load\" message (see `errorMessage`) in place of rows. */\n error?: boolean;\n /** @default \"Couldn't load options. Please try again.\" */\n errorMessage?: string;\n /** Shows a \"Load more\" button below the results when another page is available. */\n hasMore?: boolean;\n /** Disables the Load more button and shows a small spinner in it while a page is already in flight. */\n loadingMore?: boolean;\n onLoadMore?: () => void;\n /** Extra toolbar content rendered after the built-in filter dropdowns --\n * e.g. a source/level multi-select the caller owns. A plain composition\n * slot; this component has no opinion on what it renders. */\n toolbarExtra?: ReactNode;\n /**\n * Optional prefix for `data-testid` attributes on the search input\n * (`${testIdPrefix}-search`), the source toggle buttons\n * (`${testIdPrefix}-source-search` / `-lists`), each filter dropdown\n * trigger (`${testIdPrefix}-filter-<slug>`) and its options, the\n * select-all checkbox (`${testIdPrefix}-select-all`), each row\n * (`${testIdPrefix}-row-<slug>`), the Load more button\n * (`${testIdPrefix}-load-more`), and each Account lists row/count\n * (`${testIdPrefix}-list-<id>` / `${testIdPrefix}-list-count`). Omit for\n * no test-id wiring.\n */\n testIdPrefix?: string;\n}\n\n/**\n * @pattern SelectionPicker\n * @description Generic search-and-filter picker for building a selection out\n * of a larger catalog -- a search box plus filter dropdowns above a checkbox\n * table, with an optional \"Search / Account lists\" source toggle for pulling\n * in whole pre-built lists at once. The table stays empty until the user\n * actually searches or filters (no pre-loaded catalog dump), and checking a\n * row commits immediately rather than staging into a separate \"Add\n * selected\" step. Supports two data modes: a full in-memory `catalog`\n * filtered client-side (the default), or externally-computed `results` for a\n * caller whose search is server-side/async, with `loading`/`error`/\n * `hasMore`/`onLoadMore` covering that mode's states.\n * @tokens rounded-control, rounded-card, border-border-default, bg-input,\n * bg-canvas, bg-surface, shadow-raised, shadow-overlay, text-text-primary,\n * text-text-secondary, text-text-tertiary, text-text-link,\n * text-brand-primaryAction, border-brand-primaryAction, bg-brand-primaryAction,\n * bg-brand-primarySoft, bg-subtle, rounded-full, hover:bg-subtle,\n * hover:bg-canvas, hover:text-text-primary, placeholder:text-text-tertiary,\n * cursor-default\n * @dependencies lucide-react, this package's own CheckBox\n * @behavior \"Select all\" is scoped to the current search/filter results (or\n * the currently-loaded page(s) of `results`), not the whole catalog, and\n * skips lockedIds throughout so it can't toggle rows it isn't responsible\n * for. Filter dropdowns are portal-rendered and close on outside-click,\n * Escape, or scroll. Long option lists (>8) get an in-dropdown search box.\n * Row and select-all checkboxes use this package's own `CheckBox`, wired\n * with both an `onChange` and the row's own `onClick` -- `CheckBox` stops\n * click propagation before firing `onChange`, which is exactly what lets it\n * sit inside a row that toggles on its own click without double-firing.\n * @a11y Search is an <input>; result rows and the account-list menu\n * (role=\"menu\") are buttons. Escape closes the menu. Loading, empty and\n * error states announce through role=\"status\", so a consumer should NOT\n * wrap this in its own live region -- that would double-announce.\n * @usage\n * ```tsx\n * <SelectionPicker\n * catalog={advertisers}\n * selected={selected}\n * onChange={setSelected}\n * columns={[{ key: 'name', header: 'Advertiser', render: (r) => r.name }]}\n * filters={[{ label: 'Category', options: categories, value: (r) => r.category }]}\n * />\n * <SelectionPicker\n * catalog={[]}\n * results={searchResults}\n * onQueryChange={setQuery}\n * loading={status === 'loading'}\n * error={status === 'error'}\n * hasMore={hasMore}\n * loadingMore={loadingMore}\n * onLoadMore={loadMore}\n * selected={selected}\n * onChange={setSelected}\n * columns={columns}\n * filters={[]}\n * toolbarExtra={<LevelMultiSelect checked={levels} onToggle={toggleLevel} options={levelOptions} />}\n * />\n * ```\n */\nexport function SelectionPicker<T extends PickerRow>({\n catalog = [],\n selected,\n onChange,\n columns,\n filters,\n searchPlaceholder = \"Search…\",\n getChildren,\n helper,\n showInfoColumn = true,\n defaultFilters,\n requireQuery = false,\n showResultsWithoutSearch = false,\n accountLists,\n selectedListIds,\n onToggleList,\n lockedIds,\n results,\n onQueryChange,\n loading = false,\n error = false,\n errorMessage = \"Couldn't load options. Please try again.\",\n hasMore = false,\n loadingMore = false,\n onLoadMore,\n toolbarExtra,\n testIdPrefix,\n}: SelectionPickerProps<T>) {\n const hasAccountLists = !!accountLists;\n const [source, setSource] = useState<\"search\" | \"lists\">(\"search\");\n const [query, setQuery] = useState(\"\");\n const [activeFilters, setActiveFilters] = useState<Record<string, Set<string>>>(() => {\n const init: Record<string, Set<string>> = {};\n if (defaultFilters) for (const [label, opts] of Object.entries(defaultFilters)) init[label] = new Set(opts);\n return init;\n });\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n\n const selectedIds = useMemo(() => new Set(selected.map((s) => s.id)), [selected]);\n\n const toggleFilter = (label: string, opt: string) => {\n setActiveFilters((prev) => {\n const next = { ...prev };\n const set = new Set(next[label] ?? []);\n set.has(opt) ? set.delete(opt) : set.add(opt);\n next[label] = set;\n return next;\n });\n };\n\n const activeFilterCount = filters.reduce((n, f) => n + (activeFilters[f.label]?.size ?? 0), 0);\n // The table stays empty until the user actually searches or filters -- no\n // pre-loaded catalog dump on first render.\n const hasSearched = showResultsWithoutSearch || query.trim().length > 0 || (!requireQuery && activeFilterCount > 0);\n\n const filteredCatalog = useMemo(() => {\n if (!hasSearched || results !== undefined) return [];\n const q = query.trim().toLowerCase();\n return catalog.filter((row) => {\n if (q && !row.name.toLowerCase().includes(q)) return false;\n for (const f of filters) {\n const active = activeFilters[f.label];\n if (active && active.size > 0) {\n const v = f.value(row);\n if (!v || !active.has(v)) return false;\n }\n }\n return true;\n });\n }, [hasSearched, results, catalog, query, filters, activeFilters]);\n\n // Externally-supplied rows (async/server search) take over entirely when\n // given; otherwise fall back to the catalog filtered above.\n const rows = results !== undefined ? results : filteredCatalog;\n\n const addRows = (add: T[]) => {\n const toAdd = add.filter((r) => !selectedIds.has(r.id));\n if (toAdd.length) onChange([...selected, ...toAdd]);\n };\n\n /** Checking a row adds it immediately; unchecking removes it immediately\n * (no separate \"Add selected\" staging step). */\n const toggleRow = (row: T) => {\n if (selectedIds.has(row.id)) {\n onChange(selected.filter((s) => s.id !== row.id));\n } else {\n addRows([row]);\n }\n };\n\n /** Scoped to the current search/filter results, not the whole catalog --\n * \"select all\" selects everything in view, not everything that exists.\n * Locked rows are excluded throughout: they can't be toggled individually,\n * so select-all must not toggle them either. */\n const toggleable = lockedIds ? rows.filter((r) => !lockedIds.has(r.id)) : rows;\n const allSelected = toggleable.length > 0 && toggleable.every((r) => selectedIds.has(r.id));\n const someSelected = toggleable.some((r) => selectedIds.has(r.id));\n\n const toggleAll = () => {\n if (allSelected) {\n const rowIds = new Set(toggleable.map((r) => r.id));\n onChange(selected.filter((s) => !rowIds.has(s.id)));\n } else {\n addRows(toggleable);\n }\n };\n\n const rowGridCols = showInfoColumn ? \"grid-cols-[36px_1fr_44px]\" : \"grid-cols-[36px_1fr]\";\n\n return (\n <div className=\"flex flex-col gap-4\">\n {helper && (\n <>\n <p className=\"text-[13px] text-text-secondary\">{helper}</p>\n <hr className=\"-mx-5 -mt-2 border-border-default sm:-mx-6\" />\n </>\n )}\n\n {/* Source toggle -- Search (browse + cherry-pick) vs Account lists\n (apply a whole uploaded list). Only shown when account lists are\n available for this picker. */}\n {hasAccountLists && (\n <div className=\"inline-flex gap-0.5 self-start rounded-control border border-border-default bg-canvas p-0.5\">\n {(\n [\n { id: \"search\", label: \"Search\", icon: Search },\n { id: \"lists\", label: \"Account lists\", icon: List },\n ] as const\n ).map((t) => {\n const on = source === t.id;\n return (\n <button\n key={t.id}\n type=\"button\"\n onClick={() => setSource(t.id)}\n data-testid={testIdPrefix && `${testIdPrefix}-source-${t.id}`}\n className={cx(\n \"inline-flex items-center gap-1.5 rounded-[6px] px-3 py-1.5 text-[13px] font-medium transition-colors\",\n on ? \"bg-surface text-text-primary shadow-raised\" : \"text-text-secondary hover:text-text-primary\"\n )}\n >\n <t.icon size={14} aria-hidden=\"true\" />\n {t.label}\n </button>\n );\n })}\n </div>\n )}\n\n {/* Results -- no card wrapper; the toolbar and table sit directly on\n the section's own background. */}\n {source === \"search\" && (\n <div className=\"flex min-w-0 flex-col gap-3\">\n {/* Toolbar -- search and filter dropdowns directly above the table.\n Checking a row adds it immediately, so there's no separate\n add-selected step here. */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"flex h-9 min-w-[200px] flex-1 items-center gap-2 rounded-control border border-border-default bg-input px-3\">\n <Search size={15} className=\"text-text-secondary\" aria-hidden=\"true\" />\n <input\n value={query}\n onChange={(e) => {\n const next = e.target.value;\n setQuery(next);\n onQueryChange?.(next);\n }}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n data-testid={testIdPrefix && `${testIdPrefix}-search`}\n className=\"h-full flex-1 bg-transparent text-sm outline-hidden placeholder:text-text-tertiary\"\n />\n </div>\n {filters.map((f) => (\n <FilterDropdown\n key={f.label}\n filter={f}\n active={activeFilters[f.label] ?? new Set()}\n onToggle={(opt) => toggleFilter(f.label, opt)}\n testIdPrefix={testIdPrefix}\n />\n ))}\n {toolbarExtra}\n </div>\n\n {!hasSearched ? (\n <div className=\"flex flex-col items-center gap-3 rounded-card border border-dashed border-border-default py-10 text-center\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-subtle\">\n <Search size={20} className=\"text-text-tertiary\" aria-hidden=\"true\" />\n </div>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-[14px] font-semibold text-text-primary\">Search to get started</p>\n <p className=\"text-[13px] text-text-tertiary\">Use the search or filters above to find and add options.</p>\n </div>\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-control border border-border-default\">\n <div\n className={cx(\n \"grid items-center gap-2 border-b border-border-default bg-canvas px-3 py-2 text-[11px] font-semibold uppercase tracking-[0.06em] text-text-secondary\",\n rowGridCols\n )}\n >\n <CheckBox\n checked={allSelected}\n indeterminate={!allSelected && someSelected}\n disabled={toggleable.length === 0}\n onChange={toggleAll}\n ariaLabel=\"Select all\"\n testId={testIdPrefix && `${testIdPrefix}-select-all`}\n />\n <div className={cx(\"grid gap-2\", gridForColumns(columns))}>\n {columns.map((c) => (\n <span key={c.key} className={c.className}>\n {c.header}\n </span>\n ))}\n </div>\n {showInfoColumn && <span className=\"text-right\">Info</span>}\n </div>\n\n <div className=\"max-h-[360px] overflow-y-auto\">\n {loading ? (\n <div className=\"flex items-center justify-center py-6\" role=\"status\" aria-label=\"Loading\">\n <Loader2 size={18} className=\"animate-spin text-text-tertiary\" aria-hidden=\"true\" />\n </div>\n ) : error ? (\n <p className=\"px-3 py-8 text-center text-[13px] text-text-tertiary\">{errorMessage}</p>\n ) : rows.length === 0 ? (\n <div className=\"px-3 py-8 text-center text-[13px] text-text-tertiary\">\n No matches. Try a different search or filter.\n </div>\n ) : (\n rows.map((row) => {\n const isSel = selectedIds.has(row.id);\n const isLocked = lockedIds?.has(row.id) ?? false;\n const kids = getChildren?.(row) as T[] | undefined;\n const isOpen = expanded.has(row.id);\n return (\n <div key={row.id} className=\"border-t border-border-default/60 first:border-t-0\">\n <div\n onClick={isLocked ? undefined : () => toggleRow(row)}\n aria-disabled={isLocked || undefined}\n className={cx(\n \"grid items-center gap-2 px-3 py-2.5\",\n rowGridCols,\n isLocked ? \"cursor-default opacity-50\" : \"cursor-pointer hover:bg-subtle\",\n !isLocked && isSel && \"opacity-60\"\n )}\n >\n {/* Locked rows keep the checkbox column as an empty\n spacer so every row's columns stay on the same grid. */}\n {isLocked ? (\n <span aria-hidden=\"true\" />\n ) : (\n <CheckBox\n checked={isSel}\n onChange={() => toggleRow(row)}\n ariaLabel={row.name}\n testId={testIdPrefix && `${testIdPrefix}-row-${slug(row.id)}`}\n />\n )}\n <div className={cx(\"grid gap-2 text-[13px] text-text-primary\", gridForColumns(columns))}>\n {columns.map((c) => (\n <span key={c.key} className={cx(\"truncate\", c.className)}>\n {c.render(row)}\n </span>\n ))}\n </div>\n {showInfoColumn && (\n <div className=\"flex items-center justify-end\">\n {kids && kids.length > 0 ? (\n <button\n type=\"button\"\n aria-label=\"Show details\"\n onClick={(e) => {\n e.stopPropagation();\n setExpanded((p) => {\n const n = new Set(p);\n n.has(row.id) ? n.delete(row.id) : n.add(row.id);\n return n;\n });\n }}\n className=\"flex h-7 w-7 items-center justify-center rounded-control text-text-secondary hover:bg-canvas hover:text-text-primary\"\n >\n <ChevronRight size={15} className={cx(\"transition-transform\", isOpen && \"rotate-90\")} />\n </button>\n ) : (\n <span\n className=\"flex h-7 w-7 items-center justify-center text-text-tertiary\"\n title=\"No additional details\"\n >\n <Info size={14} />\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Mock drill-down children */}\n {isOpen && kids && (\n <div className=\"bg-canvas/60 pb-1.5 pl-10 pr-3\">\n {kids.map((kid) => {\n const kidSel = selectedIds.has(kid.id);\n return (\n <div\n key={kid.id}\n className=\"flex items-center justify-between gap-2 border-t border-border-default/40 py-2 first:border-t-0\"\n >\n <span className=\"truncate text-[13px] text-text-secondary\">{kid.name}</span>\n <button\n type=\"button\"\n disabled={kidSel}\n onClick={() => addRows([kid])}\n className={cx(\n \"inline-flex items-center gap-1 rounded-control px-2 py-1 text-[12px] font-medium\",\n kidSel ? \"text-text-tertiary\" : \"text-text-link hover:bg-subtle\"\n )}\n >\n {kidSel ? <Check size={13} /> : <Plus size={13} />}\n {kidSel ? \"Added\" : \"Add\"}\n </button>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n })\n )}\n </div>\n\n {!loading && !error && hasMore && (\n <button\n type=\"button\"\n onClick={onLoadMore}\n disabled={loadingMore}\n data-testid={testIdPrefix && `${testIdPrefix}-load-more`}\n className=\"flex w-full items-center justify-center gap-2 border-t border-border-default px-2 py-1.5 text-[13px] text-brand-primaryAction transition-colors hover:bg-subtle disabled:opacity-50\"\n >\n {loadingMore ? <Loader2 size={13} className=\"animate-spin\" aria-hidden=\"true\" /> : null}\n {loadingMore ? \"Loading…\" : \"Load more\"}\n </button>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Account lists -- select whole uploaded lists as advertiser sources. */}\n {source === \"lists\" && (\n <div className=\"flex min-w-0 flex-col gap-3\">\n <p className=\"text-[13px] text-text-secondary\">\n Select an account list to add all of its accounts at once. Your workspace stays in sync as the list is updated.\n </p>\n {accountLists && accountLists.length > 0 ? (\n <>\n {/* Scrolls internally so a long catalog can't push the card's\n footer off-screen. The cap is deliberately set mid-row (5 rows\n + gaps = 365px, + ~half of row 6) rather than on a row\n boundary: a partially visible row is the affordance. The faded\n edge keeps that half-row from reading as a clipping bug. */}\n <ScrollFade className=\"flex max-h-[396px] flex-col gap-2 overflow-y-auto pr-0.5\">\n {accountLists.map((list) => {\n const on = (selectedListIds ?? []).includes(list.id);\n return (\n <button\n key={list.id}\n type=\"button\"\n onClick={() => onToggleList?.(list.id)}\n aria-pressed={on}\n data-testid={testIdPrefix && `${testIdPrefix}-list-${list.id}`}\n className={cx(\n \"flex items-center gap-3 rounded-control border px-3.5 py-3 text-left transition-colors\",\n on ? \"border-brand-primaryAction bg-brand-primarySoft\" : \"border-border-default bg-surface hover:bg-subtle\"\n )}\n >\n <span\n className={cx(\n \"flex h-5 w-5 shrink-0 items-center justify-center rounded-full\",\n on ? \"text-brand-primaryAction\" : \"text-text-secondary\"\n )}\n >\n {on ? <Check size={16} /> : <Plus size={16} />}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex min-w-0 items-center gap-2\">\n <span className=\"truncate text-[14px] font-medium text-text-primary\">{list.name}</span>\n </span>\n <span className=\"block truncate text-[12px] text-text-secondary\">\n {list.count} accounts · {list.entityTypes.join(\", \")} · Updated {formatListDate(list.updatedAt)}\n </span>\n </span>\n <span className={cx(\"shrink-0 text-[12px] font-medium\", on ? \"text-brand-primaryAction\" : \"text-text-secondary\")}>\n {on ? \"Added\" : \"Add\"}\n </span>\n </button>\n );\n })}\n </ScrollFade>\n {/* Closes off the scroll area, and the total tells the user there\n was more than the ~5 rows on screen -- the faded edge says they\n can scroll, this says why. */}\n <p\n className=\"border-t border-border-default pt-2 text-right text-[12px] font-medium text-text-tertiary\"\n data-testid={testIdPrefix && `${testIdPrefix}-list-count`}\n >\n {accountLists.length} {accountLists.length === 1 ? \"list\" : \"lists\"}\n </p>\n </>\n ) : (\n <div className=\"flex flex-col items-center gap-3 rounded-card border border-dashed border-border-default py-10 text-center\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-subtle\">\n <List size={20} className=\"text-text-tertiary\" aria-hidden=\"true\" />\n </div>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-[14px] font-semibold text-text-primary\">No account lists yet</p>\n <p className=\"text-[13px] text-text-tertiary\">Account lists set up for you will appear here.</p>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\n/** Height of the softened edge, in px. Matches ~2/3 of a list row so the fade\n * reads as \"continues\" without washing out the peeking row's label. */\nconst EDGE_FADE = 44;\n\n/**\n * A scroll container whose clipped edges fade out while content is hidden past\n * them -- the cue that the list keeps going. Pair it with a max-height that lands\n * mid-row: a partially visible row is the affordance, and the fade is what keeps\n * that half-row from reading as a clipping bug.\n *\n * The fade is a mask over the content rather than a colored scrim, so it needs\n * no knowledge of the surface behind it and works in both themes.\n */\nfunction ScrollFade({ className, children }: { className?: string; children: ReactNode }) {\n const elRef = useRef<HTMLDivElement | null>(null);\n const [edges, setEdges] = useState({ top: false, bottom: false });\n\n const sync = useCallback(() => {\n const el = elRef.current;\n if (!el) return;\n const top = el.scrollTop > 2;\n const bottom = el.scrollTop + el.clientHeight < el.scrollHeight - 2;\n // Bail when unchanged -- this runs on every scroll frame.\n setEdges((prev) => (prev.top === top && prev.bottom === bottom ? prev : { top, bottom }));\n }, []);\n\n // A callback ref (rather than an effect) so this runs the moment the node\n // mounts -- the container is conditionally rendered, so it can appear long\n // after the first render. We measure right here instead of relying on\n // ResizeObserver's initial callback, which is delivered on the frame pipeline\n // and so never arrives in a backgrounded tab. The observer then handles later\n // reflows (window resize, sidebar collapse).\n const attach = useCallback(\n (el: HTMLDivElement | null) => {\n elRef.current = el;\n if (!el) return;\n sync();\n const ro = new ResizeObserver(sync);\n ro.observe(el);\n return () => {\n ro.disconnect();\n elRef.current = null;\n };\n },\n [sync]\n );\n\n /** Opaque except at whichever edge is currently hiding content. */\n const mask =\n edges.top || edges.bottom\n ? `linear-gradient(to bottom, transparent 0, #000 ${edges.top ? EDGE_FADE : 0}px, #000 calc(100% - ${\n edges.bottom ? EDGE_FADE : 0\n }px), transparent 100%)`\n : undefined;\n\n return (\n <div ref={attach} onScroll={sync} className={className} style={{ maskImage: mask, WebkitMaskImage: mask }}>\n {children}\n </div>\n );\n}\n\nfunction formatListDate(iso: string) {\n try {\n return new Date(iso).toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n } catch {\n return iso;\n }\n}\n\n/** Toolbar filter -- a button that opens a checkbox popover, so multiple\n * filter dimensions fit on one line instead of a permanent sidebar. */\nfunction FilterDropdown<T extends PickerRow>({\n filter,\n active,\n onToggle,\n testIdPrefix,\n}: {\n filter: PickerFilter<T>;\n active: Set<string>;\n onToggle: (opt: string) => void;\n testIdPrefix?: string;\n}) {\n const [open, setOpen] = useState(false);\n const [q, setQ] = useState(\"\");\n const btnRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null);\n\n // Long option lists (e.g. the market list) get an in-dropdown search box.\n const searchable = filter.options.length > 8;\n const shownOptions =\n searchable && q.trim() ? filter.options.filter((o) => o.toLowerCase().includes(q.trim().toLowerCase())) : filter.options;\n\n // Positioned in a portal (not a plain `absolute` child) so it floats above\n // the picker's own scroll container instead of being clipped by it -- an\n // `overflow-y-auto` ancestor forces the x-axis to clip too, cutting off any\n // in-flow dropdown that extends past its right edge.\n useLayoutEffect(() => {\n if (!open || !btnRef.current) return;\n const r = btnRef.current.getBoundingClientRect();\n setPos({ top: r.bottom + 6, left: r.left });\n }, [open]);\n\n useEffect(() => {\n if (!open) {\n setQ(\"\");\n return;\n }\n const onDown = (e: MouseEvent) => {\n const t = e.target as Node;\n if (!btnRef.current?.contains(t) && !menuRef.current?.contains(t)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n const onScroll = () => setOpen(false);\n window.addEventListener(\"mousedown\", onDown);\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"scroll\", onScroll, true);\n return () => {\n window.removeEventListener(\"mousedown\", onDown);\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"scroll\", onScroll, true);\n };\n }, [open]);\n\n const count = active.size;\n // Label reflects the selection: the filter's name when nothing is picked,\n // the single option's name when one is picked, or \"Multiple\" beyond that.\n const label = count === 0 ? filter.label : count === 1 ? [...active][0] : \"Multiple\";\n const filterSlug = slug(filter.label);\n\n return (\n <div className=\"relative\">\n <button\n ref={btnRef}\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-testid={testIdPrefix && `${testIdPrefix}-filter-${filterSlug}`}\n className=\"inline-flex h-9 items-center gap-1.5 whitespace-nowrap rounded-control border border-border-default bg-input px-3 text-[13px] font-medium text-text-secondary transition-colors hover:bg-subtle\"\n >\n {label}\n <ChevronDown size={13} aria-hidden=\"true\" className={cx(\"transition-transform\", open && \"rotate-180\")} />\n </button>\n\n {open &&\n pos &&\n createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n aria-label={filter.label}\n style={{ top: pos.top, left: pos.left }}\n className=\"fixed z-[80] min-w-[220px] rounded-card border border-border-default bg-surface p-2 shadow-overlay\"\n >\n {searchable && (\n <div className=\"mb-1.5 flex h-8 items-center gap-2 rounded-control border border-border-default bg-input px-2.5\">\n <Search size={14} className=\"shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <input\n autoFocus\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={`Search ${filter.label.toLowerCase()}…`}\n className=\"h-full flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary\"\n />\n </div>\n )}\n <div className={cx(\"flex flex-col gap-0.5\", searchable && \"max-h-[240px] overflow-y-auto\")}>\n {shownOptions.length === 0 ? (\n <p className=\"px-2 py-3 text-center text-[12px] text-text-secondary\">No matches.</p>\n ) : (\n shownOptions.map((opt) => {\n const on = active.has(opt);\n return (\n <label\n key={opt}\n className=\"flex cursor-pointer items-center gap-2 rounded-control px-2 py-1.5 text-[13px] text-text-primary hover:bg-subtle\"\n >\n <CheckBox\n checked={on}\n onChange={() => onToggle(opt)}\n ariaLabel={opt}\n testId={testIdPrefix && `${testIdPrefix}-filter-${filterSlug}-${slug(opt)}`}\n />\n {opt}\n </label>\n );\n })\n )}\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n\nfunction gridForColumns(columns: { className?: string }[]) {\n // Even columns by default; first column wider.\n if (columns.length <= 1) return \"grid-cols-1\";\n if (columns.length === 2) return \"grid-cols-[1.6fr_1fr]\";\n if (columns.length === 3) return \"grid-cols-[1.6fr_1fr_1fr]\";\n return \"grid-cols-[1.6fr_1fr_1fr_1fr]\";\n}\n","\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\n\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface PubBreak {\n brand: string;\n owner: string;\n tags: string[];\n spendN: number;\n pct: number;\n yoy: number | \"NEW\";\n}\n\nconst fmtM = (v: number) => (v >= 100 ? `$${Math.round(v)}M` : `$${v.toFixed(1)}M`);\n\n/** Prior-year spend derived from the current amount + YoY %, or null when\n * not computable (new this year, or a >=100% decline). */\nfunction priorYearAmt(spendN: number, yoy: number | \"NEW\"): string | null {\n if (yoy === \"NEW\" || yoy <= -100) return null;\n return fmtM(spendN / (1 + yoy / 100));\n}\n\n/** Initials-on-a-tile fallback used when no `renderLogo` is given -- no\n * image/CDN lookup, just the brand name's initials. */\nfunction initials(name: string): string {\n const words = name\n .replace(/[^a-zA-Z0-9 ]/g, \" \")\n .split(/\\s+/)\n .filter(Boolean);\n if (words.length >= 2) return (words[0][0] + words[1][0]).toUpperCase();\n return name.replace(/[^a-zA-Z0-9]/g, \"\").slice(0, 2).toUpperCase();\n}\n\nfunction Monogram({ name, size = 28 }: { name: string; size?: number }) {\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex shrink-0 items-center justify-center rounded-[6px] bg-subtle font-bold leading-none text-text-secondary\"\n style={{ width: size, height: size, fontSize: Math.round(size * 0.36) }}\n >\n {initials(name)}\n </span>\n );\n}\n\n/** Neutral descriptive chip for `tags` -- a local, minimal stand-in for this\n * package's own eventual shared Tag component; not cross-imported here\n * since Tag itself isn't part of this migration. */\nfunction BreakdownTag({ children }: { children: ReactNode }) {\n return (\n <span className=\"inline-flex items-center whitespace-nowrap rounded-full bg-subtle px-2 py-0.5 text-[11px] font-medium text-text-secondary\">\n {children}\n </span>\n );\n}\n\n/** Hover tooltip for the Previous/YoY column headers -- a simple\n * CSS-only, non-portalled bubble with a deliberate 1s hover delay (not\n * this package's own `InfoTip`, which is portalled/viewport-clamped and\n * opens immediately -- a different tradeoff for a different job: this one\n * never needs to escape a clipping ancestor, so it doesn't pay for a portal). */\nfunction DelayedTip({ label, children }: { label: string; children: ReactNode }) {\n return (\n <span className=\"group/dt relative inline-flex\" tabIndex={0} aria-label={label}>\n {children}\n <span\n role=\"tooltip\"\n className=\"pointer-events-none invisible absolute bottom-[calc(100%+6px)] left-1/2 z-40 w-[160px] -translate-x-1/2 rounded-control border border-border-default bg-surface px-2 py-1.5 text-center text-[11px] font-medium leading-snug text-text-secondary opacity-0 shadow-overlay transition-[opacity,visibility] delay-1000 duration-150 group-hover/dt:visible group-hover/dt:opacity-100 group-focus/dt:visible group-focus/dt:opacity-100\"\n >\n {label}\n </span>\n </span>\n );\n}\n\n// Shared Current/Previous/YoY column layout -- same fixed widths, sizing, and\n// coloring throughout the list.\nconst COL_CURRENT = 76;\nconst COL_PREVIOUS = 76;\nconst COL_YOY = 44;\n\nfunction MetricListHeader({ className }: { className?: string }) {\n return (\n <div className={cx(\"flex items-baseline gap-2 pb-2\", className)}>\n <span className=\"flex-1\" />\n <span className=\"flex shrink-0 items-center gap-2 pr-1.5\">\n <span className=\"text-right text-[11px] font-medium text-text-tertiary\" style={{ width: COL_CURRENT }}>\n Current\n </span>\n <DelayedTip label=\"Spend during the same time period one year ago.\">\n <span className=\"text-right text-[11px] font-medium text-text-tertiary\" style={{ width: COL_PREVIOUS }}>\n Previous\n </span>\n </DelayedTip>\n <DelayedTip label=\"Percent change from this time period vs. the same time one year ago.\">\n <span className=\"text-right text-[11px] font-medium text-text-tertiary\" style={{ width: COL_YOY }}>\n YoY\n </span>\n </DelayedTip>\n </span>\n </div>\n );\n}\n\nfunction MetricCells({ spendN, yoy }: { spendN: number; yoy: number | \"NEW\" }) {\n const prior = priorYearAmt(spendN, yoy);\n const up = yoy !== \"NEW\" && yoy >= 0;\n return (\n <span className=\"flex shrink-0 items-center gap-2 pr-1.5\">\n <span className=\"text-right text-[12px] font-bold tabular-nums text-text-primary\" style={{ width: COL_CURRENT }}>\n {fmtM(spendN)}\n </span>\n <span className=\"text-right text-[12px] font-normal tabular-nums text-text-primary\" style={{ width: COL_PREVIOUS }}>\n {prior ?? \"—\"}\n </span>\n <span className=\"flex justify-end\" style={{ width: COL_YOY }}>\n {yoy === \"NEW\" ? (\n <span className=\"rounded-full bg-status-warning/15 px-1.5 text-[10px] font-semibold text-text-warning\">NEW</span>\n ) : (\n <span className={cx(\"text-right text-[12px] font-semibold tabular-nums\", up ? \"text-text-success\" : \"text-text-danger\")}>\n {up ? \"+\" : \"−\"}\n {Math.abs(yoy)}%\n </span>\n )}\n </span>\n </span>\n );\n}\n\nexport interface PublisherBreakdownListProps {\n rows: PubBreak[];\n /** @default 10 */\n defaultVisibleCount?: number;\n /** Set false when the container already supplies its own padding. @default true */\n padded?: boolean;\n /** When provided, the truncated-list footer becomes a plain link instead of\n * the inline \"see all\" expand/collapse behavior. */\n viewAllHref?: string;\n /**\n * Custom per-row logo/avatar rendering -- e.g. a real logo-fetching hook or\n * a brand-name-to-domain favicon lookup. Defaults to a plain initials\n * monogram so the component works with zero configuration; this package\n * intentionally doesn't ship a brand -> logo/domain lookup table, since\n * that's fixture/business data, not a design-system concern.\n */\n renderLogo?: (row: PubBreak) => ReactNode;\n}\n\n/**\n * @pattern PublisherBreakdownList\n * @description Flat Current/Previous/YoY spend list, prop-driven end to end\n * -- no data fetching of its own. Row padding is configurable so it can sit\n * flush inside a bordered card or inline within an already-padded container.\n * mr-clientapps-insights-studio's analogous \"Top publishers\" UI\n * (`PublisherBreakdown.tsx`) was evaluated for reconciliation and\n * deliberately NOT merged into this component -- see the escape-hatch note\n * below. `renderLogo` lets a caller plug in real per-row logos; without it,\n * rows show a plain initials monogram.\n * @tokens text-text-primary, text-text-tertiary, text-text-secondary,\n * text-text-link, text-text-warning, text-text-success, text-text-danger,\n * border-border-default, bg-surface, bg-subtle, rounded-control, rounded-full,\n * shadow-overlay\n * @behavior Truncates to `defaultVisibleCount` rows with a \"See all (N more)\"\n * / \"Show less\" toggle, unless `viewAllHref` is given, in which case the\n * footer becomes a plain link out instead (e.g. to a full breakdown page).\n *\n * Escape hatch: mr-clientapps-insights-studio's own publisher breakdown\n * (`domains/reviews/src/components/media-spend/PublisherBreakdown.tsx`) is a\n * genuinely different component, not just a differently-styled copy of this\n * one -- a three-level Owner/Publisher/Property accordion, each level\n * independently paginated against a live API (`usePublisherBreakdown`/\n * `usePublisherBreakdownChildren`), with per-row logo fetching via a batched\n * hook. None of that -- the recursive expand/collapse tree, the live\n * fetching, the level toggle -- has an equivalent in this flat,\n * fully-synchronous, prop-driven list, and bolting it on would mean either\n * building the accordion machinery into every consumer of this component\n * (including ones that only ever wanted a flat list, like the Opportunities\n * battle card) or branching internally on which \"mode\" is active -- exactly\n * the kind of forked-with-extra-indirection outcome this package's README\n * calls out as not actually shared. Per that guidance, this component stays\n * the flat-list case only; mr-clientapps' accordion stays where it is, un-migrated.\n * @a11y Rows are buttons. One row manages tabIndex directly and a row tooltip\n * uses role=\"tooltip\", dismissed on Escape. The tooltip describes rather\n * than names, so never put a row's only label in it.\n * @usage\n * ```tsx\n * <PublisherBreakdownList rows={publishers} defaultVisibleCount={10} />\n * ```\n */\nexport function PublisherBreakdownList({ rows, defaultVisibleCount = 10, padded = true, viewAllHref, renderLogo }: PublisherBreakdownListProps) {\n const [showAll, setShowAll] = useState(false);\n const visible = showAll ? rows : rows.slice(0, defaultVisibleCount);\n const rowPad = padded ? \"px-5\" : \"\";\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <MetricListHeader className={rowPad} />\n {visible.map((p) => (\n <div key={p.brand} className={cx(\"flex items-center justify-between gap-3 border-t border-border-default/60 py-2.5 first:border-t-0\", rowPad)}>\n <div className=\"flex min-w-0 items-center gap-2.5\">\n {renderLogo ? renderLogo(p) : <Monogram name={p.brand} size={28} />}\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <span className=\"text-[14px] font-semibold text-text-primary\">{p.brand}</span>\n {p.tags.map((t) => (\n <BreakdownTag key={t}>{t}</BreakdownTag>\n ))}\n </div>\n <div className=\"truncate text-[11.5px] text-text-tertiary\">{p.owner}</div>\n </div>\n </div>\n <MetricCells spendN={p.spendN} yoy={p.yoy} />\n </div>\n ))}\n </div>\n {rows.length > defaultVisibleCount &&\n (viewAllHref ? (\n <div className={cx(\"border-t border-border-default py-3\", rowPad)}>\n <a href={viewAllHref} className=\"text-[12px] font-semibold text-text-link hover:underline\">\n See all publishers\n </a>\n </div>\n ) : (\n <div className={cx(\"flex items-center gap-2 border-t border-border-default py-3 text-[12px] text-text-tertiary\", rowPad)}>\n <span>\n Showing {visible.length} of {rows.length}\n </span>\n {!showAll ? (\n <button type=\"button\" onClick={() => setShowAll(true)} className=\"font-semibold text-text-link hover:underline\">\n See all ({rows.length - defaultVisibleCount} more)\n </button>\n ) : (\n <button type=\"button\" onClick={() => setShowAll(false)} className=\"font-semibold text-text-link hover:underline\">\n Show less\n </button>\n )}\n </div>\n ))}\n </div>\n );\n}\n","import { type ButtonHTMLAttributes, type ReactNode, forwardRef } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Loader2 } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\n// text-brand-onprimary / text-status-onstatus are lowercase on purpose: that's\n// how @mediaradar/design-tokens' theme.css names them. insights-studio-prototype's\n// camelCase onPrimary/onStatus classes only worked through its own local\n// aliases (same values), which other apps don't have.\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-control transition-all duration-(--mr-motion-duration-interactive) ease-interactive disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-hidden focus-visible:ring-0\",\n {\n variants: {\n variant: {\n primary: \"bg-brand-primaryAction text-brand-onprimary hover:brightness-110\",\n // border-strong, not border-interactive. The interactive token is #6b6358\n // -- 5.9:1 against the surface, nearly as dark as body text -- which is\n // right for an input the eye must find in a form, and far too heavy for\n // a button sitting beside other buttons. It reads heaviest on icon-only,\n // where there is least fill inside the line to balance it.\n secondary: \"bg-surface text-text-primary border border-border-strong hover:bg-subtle hover:border-border-interactive\",\n ghost: \"text-text-primary hover:bg-subtle\",\n danger: \"bg-status-danger text-status-onstatus hover:brightness-110\",\n // Quiet destructive: neutral at rest, red only on hover. This is what\n // the product actually reaches for -- nearly every hand-rolled\n // destructive control is an icon that reddens on hover, while filled\n // `danger` is right only for the confirm button in a dialog the user\n // already opened.\n dangerGhost: \"text-text-secondary hover:bg-subtle hover:text-text-danger\",\n link: \"text-text-link underline-offset-4 hover:underline px-0\",\n },\n // Type scales with the box. One size across all three left xs cramped --\n // 14px inside a 24px box leaves five pixels above and below, so the label\n // fills the button instead of sitting in it.\n size: {\n xs: \"h-6 px-2 text-xs\",\n sm: \"h-8 px-3 text-sm\",\n md: \"h-10 px-4 text-sm\",\n },\n // Shape is orthogonal to size. As a fourth SIZE, `icon` could only ever\n // be one dimension, so an icon button never lined up with the labelled\n // buttons beside it in a toolbar. As a shape it squares the box at\n // whichever height you picked.\n iconOnly: {\n true: \"p-0\",\n false: \"\",\n },\n },\n compoundVariants: [\n { size: \"xs\", iconOnly: true, class: \"w-6\" },\n { size: \"sm\", iconOnly: true, class: \"w-8\" },\n { size: \"md\", iconOnly: true, class: \"w-10\" },\n // A boxed button is a target you aim at, so its label carries the weight\n // of one. `link` sits inline in a sentence, where semibold reads as\n // emphasis on the words rather than as a control.\n { variant: [\"primary\", \"secondary\", \"ghost\", \"danger\", \"dangerGhost\"], class: \"font-semibold\" },\n { variant: \"link\", class: \"font-medium h-auto p-0\" },\n ],\n defaultVariants: {\n variant: \"primary\",\n size: \"md\",\n iconOnly: false,\n },\n }\n);\n\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n /**\n * Render the button styling onto the single child element instead of a\n * `<button>` (e.g. a router `<Link>` or an `<a>`). The child must be exactly\n * one React element; it keeps its own tag, content and semantics.\n */\n asChild?: boolean;\n /**\n * Shows a spinner in place of the leading edge and disables the button.\n * With `asChild` there is no spinner (the child owns its content, and a\n * spinner belongs inside a real `<button>`): `loading` only sets\n * `aria-busy` and forwards `disabled` to the child, which only has an\n * effect on elements that support it -- an `<a>` stays clickable, so block\n * navigation yourself while loading.\n */\n loading?: boolean;\n /** Button label and/or icon. With `asChild`, the single element that receives the button styling. */\n children?: ReactNode;\n}\n\n/**\n * @pattern Button\n * @description The one control for every clickable action, from the main call\n * to action on a screen down to a quiet toolbar utility. Six variants\n * (primary, secondary, ghost, danger, dangerGhost, link) across three sizes\n * (xs, sm, md), labelled or icon-only.\n * Supports polymorphic rendering via `asChild` (Radix Slot) to apply button\n * styling to a different element, e.g. a router `<Link>`. Also exports the\n * raw `buttonVariants` cva function for consumers composing button styling\n * onto something other than this component.\n * @tokens bg-brand-primaryAction, text-brand-onprimary, bg-surface, text-text-primary, border-border-strong, hover:border-border-interactive, hover:bg-subtle, bg-status-danger, text-status-onstatus, text-text-secondary, hover:text-text-danger, text-text-link, rounded-control, duration-(--mr-motion-duration-interactive), ease-interactive\n * @dependencies class-variance-authority, @radix-ui/react-slot, lucide-react\n * @variant primary - The one primary action on a screen. Solid brand fill.\n * @variant secondary - Any other real action competing for attention (Cancel, Export). Bordered, neutral fill.\n * @variant ghost - Low-emphasis action inside a dense toolbar or row where a border would add visual noise.\n * @variant danger - Filled red. Only for a confirmed destructive action, typically the confirm button in a dialog. Never pair with `primary` in the same control group.\n * @variant dangerGhost - Neutral at rest, red on hover. For a destructive affordance inline in a row or toolbar -- what the product reaches for far more often than filled danger.\n * @variant link - Reads as inline text, not a control. Use inside body copy or where a full button would overpower the surrounding content.\n * @behavior `disabled` removes pointer events entirely (not just a style\n * change) and dims to 40% opacity. Focus handling is a deliberate exception:\n * most interactive components use a visible `focus-visible:outline-2` ring,\n * but Button suppresses it (`focus-visible:outline-hidden focus-visible:ring-0`)\n * and relies on its per-variant hover/brightness treatment instead. `loading`\n * implies `disabled` (and sets `aria-busy`), since a control mid-submit\n * shouldn't accept another click. `asChild` renders only the child element,\n * through Radix `Slot`, with the button classes, ref and remaining props\n * merged onto it -- no wrapping `<button>`. With `asChild`, `loading` draws\n * no spinner; it sets `aria-busy` and forwards `disabled`, which an `<a>`\n * ignores, so a loading link stays clickable unless the caller blocks it.\n * @a11y Renders a native <button>, so it keeps native keyboard behaviour\n * (with `asChild`, the child element's own semantics apply instead).\n * `loading` sets aria-busy, and the spinner is aria-hidden. Icon-only\n * usage needs an aria-label from the caller -- nothing here supplies one.\n * @use when the user is triggering an action in place -- saving, applying,\n * confirming, opening a dialog, running an export.\n * @use when you need a destructive affordance: dangerGhost inline in a row or\n * toolbar, danger only as the confirm button in a dialog already opened.\n * @use when an action sits inside a sentence -- variant=\"link\", which drops\n * the box and the semibold weight so it does not read as emphasis.\n * @use when the action is icon-only in a dense toolbar -- iconOnly squares the\n * box at whichever size you picked, so it lines up with labelled buttons\n * beside it. Supply an aria-label; nothing here does.\n * @avoid when the control navigates to a different route -- render a real link\n * via asChild, so middle-click, right-click and open-in-new-tab keep working.\n * variant=\"link\" styles a button as text; it does not make a button a link.\n * @avoid when there is already a primary on the screen -- a second primary\n * means neither reads as the main action. Use secondary or ghost.\n * @avoid when the control toggles a persistent on/off state -- use CheckBox or\n * a switch. A button fires; it does not hold a state.\n * @avoid when you are about to hand-roll a button with raw classes. There is\n * no case this does not cover, and every copy is a divergence in hover, focus,\n * disabled and loading behaviour at once.\n * @usage\n * ```tsx\n * <Button variant=\"primary\" size=\"md\">Save changes</Button>\n * <Button variant=\"dangerGhost\" size=\"sm\" iconOnly aria-label=\"Remove row\"><X size={15} /></Button>\n * <Button variant=\"secondary\" size=\"sm\">Cancel</Button>\n * <Button variant=\"danger\">Delete</Button>\n * <Button variant=\"primary\" loading>Saving…</Button>\n * <Button asChild variant=\"secondary\"><a href=\"/reports\">View reports</a></Button>\n * ```\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, iconOnly, asChild = false, loading = false, disabled, children, ...props }, ref) => {\n const shared = {\n className: cn(buttonVariants({ variant, size, iconOnly, className })),\n disabled: disabled || loading,\n \"aria-busy\": loading || undefined,\n ...props,\n };\n // Slot needs exactly one child element. The spinner can't sit beside it:\n // React counts even a `false` from `{loading && ...}` as a child, which is\n // what made every `asChild` render throw before 0.12.0.\n if (asChild) {\n return (\n <Slot ref={ref} {...shared}>\n {children}\n </Slot>\n );\n }\n return (\n <button ref={ref} {...shared}>\n {loading && <Loader2 className=\"size-4 shrink-0 animate-spin\" aria-hidden=\"true\" />}\n {children}\n </button>\n );\n }\n);\nButton.displayName = \"Button\";\n\nexport { buttonVariants };\n","import { Button } from \"./Button\";\nimport { cn } from \"./cn\";\n\nexport interface FilterDropdownFooterProps {\n /** Omit to hide the Clear All action for dropdowns that don't need it. */\n onClear?: () => void;\n /** Fires when the primary action is pressed. */\n onApply: () => void;\n clearLabel?: string;\n applyLabel?: string;\n}\n\n/**\n * @pattern FilterDropdownFooter\n * @description Fixed Apply/Clear All footer for quick-filter dropdowns —\n * pinned below the (independently scrollable) option list so it's always\n * visible. Shared by the Media/Advertiser/Date/Group By/Time Increment quick\n * filters on Sports Dashboard, Publisher Intel, and Opportunities.\n * @tokens border-border-default\n * @a11y Clear and Apply are real Buttons with visible text as their accessible\n * names, in that DOM order. It adds no roles or live regions of its own --\n * the menu that contains it owns dismissal and focus.\n * @usage\n * ```tsx\n * <FilterDropdownFooter onApply={handleApply} onClear={handleClear} />\n * ```\n */\nexport function FilterDropdownFooter({\n onClear,\n onApply,\n clearLabel = \"Clear all\",\n applyLabel = \"Apply\",\n}: FilterDropdownFooterProps) {\n return (\n <div\n className={cn(\n \"flex items-center gap-2 border-t border-border-default p-2\",\n onClear ? \"justify-between\" : \"justify-end\"\n )}\n >\n {onClear && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onClear}>\n {clearLabel}\n </Button>\n )}\n <Button type=\"button\" variant=\"primary\" size=\"sm\" onClick={onApply}>\n {applyLabel}\n </Button>\n </div>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"./Button\";\nimport { CheckBox } from \"./CheckBox\";\n\nexport interface NameListModalProps {\n title: string;\n initialName: string;\n submitLabel: string;\n onCancel: () => void;\n /**\n * Called with the trimmed name, and the state of `options` when any were\n * given. A handler that only takes the name stays valid -- TypeScript lets\n * a function ignore trailing parameters -- so existing callers are\n * unaffected.\n */\n onSubmit: (name: string, checked: Record<string, boolean>) => void;\n /**\n * Relabels the name field, for dialogs that name something other than a\n * list (e.g. \"View name\").\n */\n fieldLabel?: string;\n /** Placeholder for the name field, paired with `fieldLabel`. */\n placeholder?: string;\n /**\n * Optional checkboxes below the name field -- e.g. \"Set as default\" or\n * \"Enable email alerts\". Their state is handed to `onSubmit` as the second\n * argument, keyed by `key`. `initial` sets the starting state.\n */\n options?: { key: string; label: string; initial?: boolean }[];\n}\n\n/**\n * @pattern NameListModal\n * @description Create/rename dialog — a name field, and optionally a few\n * checkboxes under it. Shared by the Account Lists table and the list detail\n * page so create/rename look identical; `fieldLabel`/`placeholder` relabel it\n * for dialogs that name something other than a list.\n * @tokens bg-scrim, rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, rounded-control, bg-input, focus:border-brand-primaryAction\n * @behavior Escape closes the dialog via `onCancel`, same as clicking the\n * scrim backdrop. Submit is disabled until the name is non-empty (trimmed).\n * When `options` are given they render as CheckBox rows below the field, and\n * their state comes back as `onSubmit`'s second argument -- a handler that\n * only takes the name stays valid.\n * @a11y role=\"dialog\" with aria-modal, labelled by its title. The name field\n * takes focus on open and Escape closes via onCancel. Focus is NOT trapped\n * and NOT restored to the opener on close -- confirmed in the source -- so\n * a consumer that needs either must supply it around this component.\n * @usage\n * ```tsx\n * <NameListModal title=\"Rename list\" initialName={list.name} submitLabel=\"Save\" onCancel={close} onSubmit={rename} />\n * ```\n */\nexport function NameListModal({\n title,\n initialName,\n submitLabel,\n onCancel,\n onSubmit,\n fieldLabel = \"List name\",\n placeholder = \"e.g. Q4 prospecting targets\",\n options,\n}: NameListModalProps) {\n const [name, setName] = useState(initialName);\n const [checked, setChecked] = useState<Record<string, boolean>>(() =>\n Object.fromEntries((options ?? []).map((o) => [o.key, !!o.initial]))\n );\n const toggle = (key: string) => setChecked((c) => ({ ...c, [key]: !c[key] }));\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onCancel();\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [onCancel]);\n\n return createPortal(\n // bg-scrim, not a literal: design-tokens gained a scrim token in 2.5.0.\n // No in-data-[theme=dark] override needed any more -- the token redefines\n // itself under that attribute in dark.css, so one class covers both themes.\n <div\n className=\"fixed inset-0 z-70 flex items-center justify-center bg-scrim px-4\"\n onMouseDown={(e) => e.target === e.currentTarget && onCancel()}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n className=\"w-full max-w-[420px] rounded-card border border-border-default bg-surface p-5 shadow-overlay\"\n >\n <h2 className=\"text-[16px] font-semibold text-text-primary\">{title}</h2>\n <div className=\"mt-4 flex flex-col gap-1.5\">\n <label htmlFor=\"account-list-name\" className=\"text-[12px] font-medium text-text-secondary\">\n {fieldLabel}\n </label>\n <input\n id=\"account-list-name\"\n autoFocus\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={placeholder}\n className=\"h-10 rounded-control border border-border-default bg-input px-3 text-sm outline-hidden focus:border-brand-primaryAction\"\n />\n </div>\n {options && options.length > 0 && (\n <div className=\"mt-4 flex flex-col gap-2.5\">\n {options.map((o) => (\n <label key={o.key} className=\"flex cursor-pointer items-center gap-2.5 text-[13px] text-text-primary\">\n <CheckBox checked={!!checked[o.key]} onChange={() => toggle(o.key)} ariaLabel={o.label} />\n {o.label}\n </label>\n ))}\n </div>\n )}\n <div className=\"mt-5 flex items-center justify-end gap-2\">\n <Button variant=\"secondary\" onClick={onCancel}>\n Cancel\n </Button>\n <Button disabled={!name.trim()} onClick={() => onSubmit(name.trim(), checked)}>\n {submitLabel}\n </Button>\n </div>\n </div>\n </div>,\n document.body\n );\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"./cn\";\n\n/**\n * Which stroke a chip trigger carries.\n * - `box` : the boxed two-line chip (caption over value), on the default\n * border. The common filter-bar chip.\n * - `inline` : the same white fill with a darker stroke, for chips sitting\n * directly on the warm canvas with no boxed shell around them.\n */\nexport type ChipVariant = \"box\" | \"inline\";\n\n/** Shared styling for filter-bar chip triggers, so every dropdown chip matches. */\nexport function chipTriggerClass(variant: ChipVariant = \"box\") {\n return cn(\n \"flex h-11 items-center gap-2 rounded-control border bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n // Both variants sit on the input fill. `inline` carries the darker stroke\n // so it still reads as a control against the warm canvas with no boxed\n // shell behind it.\n variant === \"inline\" ? \"border-border-strong\" : \"border-border-default\"\n );\n}\n\nexport interface ChipContentProps {\n /** Small uppercase label above the value. */\n caption: string;\n /** The current selection, shown below the caption. */\n value: ReactNode;\n /** Optional leading icon rendered before the caption/value stack. */\n icon?: ReactNode;\n}\n\n/**\n * @pattern ChipTrigger\n * @description Shared foundation for filter-bar chip triggers — pairs\n * `chipTriggerClass` with `ChipContent` for the caption/value/icon layout, so\n * every dropdown chip across the app matches.\n * @tokens rounded-control, bg-input, border-border-default, border-border-strong, text-text-secondary, text-text-tertiary, text-text-primary, hover:bg-subtle, focus-visible:outline-border-focus, hover:text-text-primary\n * @behavior `chipTriggerClass` takes a `ChipVariant`: `box` (default, the\n * boxed two-line chip on the default border) or `inline` (same fill, darker\n * stroke, for chips sitting directly on the canvas). It is an argument to\n * that function, not a prop on `ChipContent`.\n * Provides only the shared `focus-visible:outline-2` keyboard-focus\n * treatment every dropdown trigger depends on — open/close, Escape, and\n * outside-click dismissal all live in each consumer, not here. A new dropdown\n * built on `chipTriggerClass` has to implement its own dismissal handling.\n * @a11y `chipTriggerClass` supplies only the shared focus-visible outline.\n * Roles, aria-expanded and dismissal all belong to the consumer's own\n * trigger -- this styles a control, it does not make one.\n * @usage\n * ```tsx\n * <button className={chipTriggerClass(\"box\")}>\n * <ChipContent caption=\"Media Type\" value=\"All\" />\n * </button>\n * ```\n */\nexport function ChipContent({ caption, value, icon }: ChipContentProps) {\n const stack = (\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">{caption}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n );\n if (icon) {\n return (\n <span className=\"flex items-center gap-2\">\n <span className=\"shrink-0 text-text-tertiary\">{icon}</span>\n {stack}\n </span>\n );\n }\n return stack;\n}\n","import { CircleSlash, X } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\ninterface ChipLike {\n key: string;\n label: string;\n groupLabel: string;\n}\n\nexport interface FilterChipBarProps<T extends ChipLike> {\n /** Any `{ key, label, groupLabel }` shape — only those fields are read. */\n chips: T[];\n onRemove: (chip: T) => void;\n onClearAll: () => void;\n /**\n * Chip keys that are kept but not applied (e.g. a filter the active\n * workspace can't resolve). Rendered inactive, still removable.\n */\n parkedKeys?: Set<string>;\n}\n\n/**\n * @pattern FilterChipBar\n * @description Applied-filter chips — wrap freely across as many rows as\n * needed, every chip shown. Each chip reveals its filter category on hover\n * (tooltip + outline). \"Clear all\" trails the chips. Generic over the\n * page's own chip type — only the shared key/label/groupLabel fields are\n * used.\n * @tokens rounded-full, bg-subtle, text-text-secondary, text-text-link, text-text-tertiary, bg-text-primary, border-border-default, group-hover:bg-border-default, group-hover:ring-border-interactive, group-hover:text-text-primary, group-hover:text-text-secondary, hover:text-text-primary, shadow-raised, text-surface\n * @dependencies lucide-react\n * @behavior A parked chip (key in `parkedKeys`) renders with no fill and a\n * dashed edge instead of the solid applied style, and its hover tooltip\n * reads \"Not in this workspace\" instead of the filter's group label.\n * @a11y Each chip's remove control is a button with its own aria-label naming\n * what it clears; the chip's icon is aria-hidden. An overflow tooltip uses\n * role=\"tooltip\", which describes rather than labels.\n * @usage\n * ```tsx\n * <FilterChipBar chips={activeChips} onRemove={removeChip} onClearAll={clearAll} />\n * ```\n */\nexport function FilterChipBar<T extends ChipLike>({ chips, onRemove, onClearAll, parkedKeys }: FilterChipBarProps<T>) {\n if (chips.length === 0) return null;\n\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 border-t border-border-default pt-2.5\">\n {chips.map((c) => (\n <Chip\n key={c.key}\n label={c.label}\n groupLabel={c.groupLabel}\n parked={!!parkedKeys?.has(c.key)}\n onRemove={() => onRemove(c)}\n />\n ))}\n <button type=\"button\" onClick={onClearAll} className=\"ml-1 text-[12px] font-medium text-text-link hover:underline\">\n Clear all\n </button>\n </div>\n );\n}\n\nfunction Chip({\n label,\n groupLabel,\n parked,\n onRemove,\n}: {\n label: string;\n groupLabel: string;\n parked: boolean;\n onRemove: () => void;\n}) {\n return (\n <span className=\"group relative inline-flex\">\n <span\n className={cn(\n \"flex items-center gap-1 rounded-full px-2.5 py-1 text-[12px] font-medium ring-1 transition-colors\",\n parked\n ? // No fill, dashed edge, muted label: reads as \"held, not acting on\n // anything\" against the solid applied chips beside it.\n \"border border-dashed border-border-default bg-transparent text-text-tertiary ring-transparent group-hover:text-text-secondary\"\n : \"bg-subtle text-text-secondary ring-transparent group-hover:bg-border-default group-hover:text-text-primary group-hover:ring-border-interactive\"\n )}\n >\n {parked && <CircleSlash size={11} aria-hidden=\"true\" className=\"shrink-0 text-text-tertiary\" />}\n {label}\n <button\n type=\"button\"\n onClick={onRemove}\n aria-label={`Remove ${groupLabel}: ${label}`}\n className=\"text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <X size={12} />\n </button>\n </span>\n <span\n role=\"tooltip\"\n className=\"pointer-events-none absolute bottom-full left-1/2 z-20 mb-1.5 -translate-x-1/2 whitespace-nowrap rounded-md bg-text-primary px-2 py-1 text-[11px] font-medium text-surface opacity-0 shadow-raised transition-opacity duration-150 group-hover:opacity-100\"\n >\n {parked ? \"Not in this workspace\" : groupLabel}\n </span>\n </span>\n );\n}\n","import { ArrowUp, ArrowDown, ArrowUpDown } from \"lucide-react\";\nimport { cn } from \"./cn\";\nimport type { SortDir } from \"./tableSort\";\n\nexport interface SortButtonProps<K extends string> {\n label: string;\n sortKey: K;\n /** Current sort; a null `key` renders every SortButton inactive. See `sortProp`. */\n sort: { key: K | null; dir: SortDir };\n onSort: (key: K) => void;\n /** True when there are no rows to order — hides the arrow, drops the click. */\n disabled?: boolean;\n}\n\n/**\n * @pattern SortButton\n * @description Design-system rule: every sortable table column header uses\n * this exact icon/color treatment. Sortable-but-inactive columns show a\n * neutral ArrowUpDown in text-tertiary at half opacity, coming up to full on\n * hover so the column reads as clickable; the active column swaps to a\n * direction arrow (ArrowUp/ArrowDown) colored with the brand action blue.\n * @tokens text-text-tertiary, text-brand-primaryAction, hover:text-text-primary\n * @dependencies lucide-react\n * @behavior Pair with `cycleSort`/`sortProp` (exported alongside) for the\n * standard three-state cycle — sort, reverse, then unsorted. `disabled` keeps\n * the column's inherited header color rather than dimming it — the column\n * isn't unavailable, there's just no data under it.\n * @a11y Renders a <button> and sets aria-sort on it. Intended for a table header\n * cell -- put it inside the <th> rather than replacing it, so the sort\n * state stays associated with the column for screen readers.\n * @usage\n * ```tsx\n * const [sort, setSort] = useState<SortState<'spend'>>(null)\n * <SortButton label=\"Spend\" sortKey=\"spend\" sort={sortProp(sort)} onSort={(k) => setSort(cycleSort(sort, k))} />\n * ```\n */\nexport function SortButton<K extends string>({ label, sortKey, sort, onSort, disabled = false }: SortButtonProps<K>) {\n const active = !disabled && sort.key === sortKey;\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={() => onSort(sortKey)}\n aria-sort={active ? (sort.dir === \"asc\" ? \"ascending\" : \"descending\") : \"none\"}\n className={cn(\n // text-left overrides the UA default on <button>, which would centre a\n // label that wraps onto two lines, out of step with the column under it.\n // `uppercase` is NOT this control imposing a treatment -- it is\n // restoring one. Every table header row sets uppercase on the <tr>,\n // and a <button> does not inherit text-transform from its parent\n // (measured: the <th> computes `uppercase`, the button inside it\n // computes `none`), so without this a sortable label renders\n // sentence case beside caps neighbours in the same band.\n //\n // Letter-spacing DOES inherit, which is why no tracking is set here.\n // This control used to set its own `tracking-wide` while every\n // header row sets `tracking-wider`, so sortable labels rendered\n // subtly tighter than the fixed headers next to them. A control\n // should carry exactly the properties that do not inherit, and\n // nothing more.\n \"group inline-flex items-center gap-1 text-left uppercase transition-colors\",\n !disabled && \"hover:text-text-primary\"\n )}\n >\n {label}\n {!disabled &&\n (active ? (\n sort.dir === \"asc\" ? (\n <ArrowUp size={12} className=\"shrink-0 text-brand-primaryAction\" />\n ) : (\n <ArrowDown size={12} className=\"shrink-0 text-brand-primaryAction\" />\n )\n ) : (\n <ArrowUpDown\n size={12}\n className=\"shrink-0 text-text-tertiary opacity-50 transition-opacity group-hover:opacity-100\"\n />\n ))}\n </button>\n );\n}\n","// Three-state column sorting: the first click sorts by that column, the\n// second reverses it, the third clears the sort and hands the rows back to\n// their natural order. `null` is that third state. Every sortable table\n// cycles this way; keeping it in one place stops the shapes drifting apart.\n\nexport type SortDir = \"asc\" | \"desc\";\n\n/** An active column and direction, or `null` for the unsorted state. */\nexport type SortState<K extends string> = { key: K; dir: SortDir } | null;\n\n/**\n * The state after clicking `key`. `firstDir` is what the column opens on,\n * since the useful first look differs by column: counts and dates want the\n * largest or newest first, names want A→Z.\n */\nexport function cycleSort<K extends string>(\n current: SortState<K>,\n key: K,\n firstDir: SortDir = \"desc\"\n): SortState<K> {\n if (!current || current.key !== key) return { key, dir: firstDir };\n if (current.dir === firstDir) return { key, dir: firstDir === \"desc\" ? \"asc\" : \"desc\" };\n return null;\n}\n\n/**\n * `SortState` in the shape SortButton takes. SortButton wants a non-null\n * object and reads `key: null` as \"no column active\".\n */\nexport function sortProp<K extends string>(sort: SortState<K>): { key: K | null; dir: SortDir } {\n return sort ?? { key: null, dir: \"desc\" };\n}\n","import { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\n/** Compact page window: all pages up to 7, otherwise 1 … current±1 … last. */\nexport function pageWindow(current: number, total: number): (number | string)[] {\n if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);\n const keep = new Set([1, total, current, current - 1, current + 1]);\n const pages = [...keep].filter((p) => p >= 1 && p <= total).sort((a, b) => a - b);\n const out: (number | string)[] = [];\n let prev = 0;\n for (const p of pages) {\n if (p - prev > 1) out.push(`gap-${p}`);\n out.push(p);\n prev = p;\n }\n return out;\n}\n\nexport interface PagerProps {\n /** The current page, 1-indexed. */\n page: number;\n totalPages: number;\n onPage: (p: number) => void;\n}\n\n/**\n * @pattern Pager\n * @description Compact prev/next pager with a windowed page-number list —\n * shows every page up to 7 total, otherwise 1 … current±1 … last with\n * ellipsis gaps. Shared by My Exports and Account Matcher.\n * @tokens rounded-control, text-text-secondary, bg-brand-primaryAction, text-brand-onprimary, hover:bg-subtle, hover:text-text-primary, text-text-tertiary\n * @dependencies lucide-react\n * @a11y Page controls are buttons with their own aria-labels, and the current\n * page is marked with aria-current. Don't relabel them with visible text\n * alone -- the labels are what a screen reader announces.\n * @usage\n * ```tsx\n * <Pager page={page} totalPages={totalPages} onPage={setPage} />\n * ```\n */\nexport function Pager({ page, totalPages, onPage }: PagerProps) {\n const btn = \"flex h-8 min-w-8 items-center justify-center rounded-control px-2 text-[13px] transition-colors\";\n return (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => onPage(page - 1)}\n disabled={page === 1}\n aria-label=\"Previous page\"\n className={cn(btn, \"text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30\")}\n >\n <ChevronLeft size={16} />\n </button>\n {pageWindow(page, totalPages).map((p) =>\n typeof p === \"string\" ? (\n <span key={p} className=\"px-1 text-[13px] text-text-tertiary\">\n …\n </span>\n ) : (\n <button\n key={p}\n type=\"button\"\n onClick={() => onPage(p)}\n aria-current={p === page ? \"page\" : undefined}\n className={cn(\n btn,\n p === page\n ? \"bg-brand-primaryAction font-semibold text-brand-onprimary\"\n : \"text-text-secondary hover:bg-subtle hover:text-text-primary\"\n )}\n >\n {p}\n </button>\n )\n )}\n <button\n type=\"button\"\n onClick={() => onPage(page + 1)}\n disabled={page === totalPages}\n aria-label=\"Next page\"\n className={cn(btn, \"text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30\")}\n >\n <ChevronRight size={16} />\n </button>\n </div>\n );\n}\n","import { cn } from \"./cn\";\n\n/**\n * First 1–2 word initials of a workspace name. \"All data workspace\" resolves\n * to \"AD\" through the same rule, so the unscoped default reads as a peer of\n * the named workspaces rather than a special case.\n */\nfunction workspaceInitials(name: string) {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return \"·\";\n if (words.length === 1) return words[0].slice(0, 2).toUpperCase();\n return (words[0][0] + words[1][0]).toUpperCase();\n}\n\nconst SIZES = {\n /** Matches a 15px lucide icon exactly, so a workspace name in a menu row\n * left-aligns with labels in icon-led rows above and below it. */\n xs: \"h-[15px] w-[15px] rounded-[4px] text-[8px] tracking-tight\",\n sm: \"h-6 w-6 text-[10px]\",\n md: \"h-7 w-7 text-[11px]\",\n lg: \"h-11 w-11 text-[15px]\",\n} as const;\n\nexport interface WorkspaceAvatarProps {\n /** Omit for the unscoped \"All data workspace\". */\n name?: string;\n size?: keyof typeof SIZES;\n}\n\n/**\n * @pattern WorkspaceAvatar\n * @description The square tile that identifies a workspace in a switch\n * list — first 1–2 word initials of the workspace name. Pass no name for\n * the unscoped \"All data workspace\", which renders \"AD\" through the same\n * rule so the unscoped default reads as a peer of named workspaces rather\n * than a special case.\n * @tokens rounded-control, bg-subtle, text-text-secondary\n * @usage\n * ```tsx\n * <WorkspaceAvatar name=\"Capital One\" size=\"sm\" />\n * ```\n */\nexport function WorkspaceAvatar({ name, size = \"md\" }: WorkspaceAvatarProps) {\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-control bg-subtle font-semibold leading-none text-text-secondary\",\n SIZES[size]\n )}\n >\n {workspaceInitials(name ?? \"All data\")}\n </span>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"./cn\";\n\nexport interface TagProps {\n /** The tag's text, e.g. \"Digital\". Keep it short: the chip doesn't wrap or truncate. */\n children: ReactNode;\n /** Extra classes merged onto the chip. */\n className?: string;\n}\n\n/**\n * @pattern Tag\n * @description Canonical descriptive tag -- a neutral chip naming what a\n * thing IS: a category, a media type, a focus area. Always neutral, never\n * semantic, never removable.\n *\n * The product separates three jobs that most systems collapse into one, by\n * who authored the label. Badge is the system's view of a thing (status,\n * count, AI-generated) and its colour means something. Tag is the thing\n * describing itself, and stays neutral. FilterChipBar is the user describing\n * what they want to see, and is the only one you can remove.\n * @use when labelling what something is -- a category, a media type, a focus\n * area, a property of the row rather than a judgement about it.\n * @avoid when the colour would mean something. A status, a count, an\n * AI marker or anything the system decided is a Badge.\n * @avoid when the user should be able to dismiss it. An applied filter is a\n * FilterChipBar chip, which belongs to the filter bar rather than to the row.\n * @avoid when there are more than a handful in a row. Tags are scanned, and a\n * dozen neutral chips read as texture rather than as information.\n * @tokens text-micro, bg-subtle, text-text-tertiary, rounded-full\n * @usage\n * ```tsx\n * <Tag>Digital</Tag>\n * ```\n */\nexport function Tag({ children, className }: TagProps) {\n return (\n <span\n className={cn(\n // text-micro and tertiary ink. The component used to sit at 11px in\n // secondary -- a step darker than the ten hand-rolled copies the audit\n // found, which had independently drifted to tertiary. Ten people\n // reaching for \"quieter\" is worth more than the component's original\n // guess: a tag names what a row IS, which is background to the row\n // itself rather than part of it.\n \"inline-flex items-center whitespace-nowrap rounded-full bg-subtle px-2 py-0.5 text-micro font-medium text-text-tertiary\",\n className\n )}\n >\n {children}\n </span>\n );\n}\n","import { ChevronDown, ChevronFirst, ChevronLast, ChevronLeft, ChevronRight } from 'lucide-react'\nimport { cn } from './cn'\nimport { pageWindow } from './Pager'\n\n/**\n * @pattern TablePagination\n * @description Full table-footer pagination bar: a rows-per-page select, a\n * first/prev/pages/next/last pager, and the resolved \"1 – 25 of N results\"\n * range. Owns no state — the host page holds `page` and `perPage` so the\n * paged slice and the bar can't disagree.\n * @tokens rounded-control, border-border-default, bg-input, text-text-primary, text-text-secondary, text-text-tertiary, bg-brand-primaryAction, text-brand-onprimary, hover:bg-subtle, hover:text-text-primary, focus:outline-border-focus\n * @behavior The current page is filled with the brand action color (matching\n * the Contacts pager). First/prev disable on page 1, next/last on the last\n * page — disabled controls stay in the layout so the row never reflows.\n * Changing the per-page count reports it and leaves the host to reset to page\n * 1. With one page of results the pager still renders, so the bar's height\n * and the range readout don't come and go as filters narrow.\n * @a11y A <nav aria-label=\"Pagination\"> wrapping <button> controls, each with\n * its own aria-label (Previous/Next/Last). The chevron icons are aria-\n * hidden, so the labels are the only accessible names -- don't override\n * them with visible text alone.\n * @usage\n * ```tsx\n * <TablePagination\n * page={page}\n * perPage={perPage}\n * totalItems={matching.length}\n * onPageChange={setPage}\n * onPerPageChange={(n) => { setPerPage(n); setPage(1) }}\n * itemLabel=\"results\"\n * />\n * ```\n */\nexport function TablePagination({\n page,\n perPage,\n totalItems,\n onPageChange,\n onPerPageChange,\n perPageOptions = [25, 50, 100],\n itemLabel = 'results',\n className,\n}: {\n page: number\n perPage: number\n totalItems: number\n onPageChange: (page: number) => void\n onPerPageChange: (perPage: number) => void\n perPageOptions?: number[]\n itemLabel?: string\n className?: string\n}) {\n const totalPages = Math.max(1, Math.ceil(totalItems / perPage))\n const current = Math.min(page, totalPages)\n const rangeStart = totalItems === 0 ? 0 : (current - 1) * perPage + 1\n const rangeEnd = Math.min(current * perPage, totalItems)\n\n const btn =\n 'flex h-8 min-w-8 items-center justify-center rounded-control px-2 text-[13px] transition-colors'\n const stepBtn = cn(\n btn,\n 'text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30'\n )\n\n return (\n <div className={cn('flex flex-wrap items-center justify-between gap-x-4 gap-y-2', className)}>\n {/* Rows per page */}\n <label className=\"flex items-center gap-2 text-[13px] text-text-secondary\">\n <span className=\"relative\">\n <select\n value={perPage}\n onChange={(e) => onPerPageChange(Number(e.target.value))}\n aria-label=\"Items per page\"\n className=\"appearance-none rounded-control border border-border-default bg-input py-1 pl-2.5 pr-7 text-[13px] font-medium text-text-primary focus:outline focus:outline-2 focus:outline-border-focus\"\n >\n {perPageOptions.map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n <ChevronDown\n size={13}\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-text-secondary\"\n />\n </span>\n items per page\n </label>\n\n {/* Pager */}\n <nav className=\"flex items-center gap-1\" aria-label=\"Pagination\">\n <button\n type=\"button\"\n onClick={() => onPageChange(1)}\n disabled={current === 1}\n aria-label=\"First page\"\n className={stepBtn}\n >\n <ChevronFirst size={16} aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n onClick={() => onPageChange(current - 1)}\n disabled={current === 1}\n aria-label=\"Previous page\"\n className={stepBtn}\n >\n <ChevronLeft size={16} aria-hidden=\"true\" />\n </button>\n {pageWindow(current, totalPages).map((p) =>\n typeof p === 'string' ? (\n <span key={p} className=\"px-1 text-[13px] text-text-tertiary\">\n …\n </span>\n ) : (\n <button\n key={p}\n type=\"button\"\n onClick={() => onPageChange(p)}\n aria-current={p === current ? 'page' : undefined}\n className={cn(\n btn,\n p === current\n ? 'bg-brand-primaryAction font-semibold text-brand-onprimary'\n : 'text-text-secondary hover:bg-subtle hover:text-text-primary'\n )}\n >\n {p}\n </button>\n )\n )}\n <button\n type=\"button\"\n onClick={() => onPageChange(current + 1)}\n disabled={current === totalPages}\n aria-label=\"Next page\"\n className={stepBtn}\n >\n <ChevronRight size={16} aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n onClick={() => onPageChange(totalPages)}\n disabled={current === totalPages}\n aria-label=\"Last page\"\n className={stepBtn}\n >\n <ChevronLast size={16} aria-hidden=\"true\" />\n </button>\n </nav>\n\n {/* Range readout */}\n <span className=\"text-[13px] text-text-tertiary tabular-nums\">\n {rangeStart.toLocaleString()} – {rangeEnd.toLocaleString()} of {totalItems.toLocaleString()} {itemLabel}\n </span>\n </div>\n )\n}\n\nexport type TablePaginationProps = Parameters<typeof TablePagination>[0]\n","import { useEffect, useMemo, useRef, useState } from 'react'\nimport { ChevronDown } from 'lucide-react'\nimport { cn } from './cn'\nimport { chipTriggerClass } from './ChipTrigger'\nimport { FilterDropdownFooter } from './FilterDropdownFooter'\n\n/**\n * @pattern DateRangePicker\n * @description Date-range control — the two-line chip (resolved span over\n * the active label, with a chevron) that opens a dropdown of rolling\n * presets plus a Custom Range (From/To month-year selects + Apply). The\n * standard date picker across the app (Sports Dashboard, Account Review,\n * Opportunities, Publisher Intel). The `presets` prop drives which rolling\n * options show — callers pass month, quarter, or year presets (e.g.\n * Publisher Intel keys them to its Time Increment); Creative Intel keeps its\n * own day-level picker (DateRangeFilter).\n * @tokens rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary, hover:bg-subtle, text-brand-primaryAction, bg-input, rounded-control, focus:border-border-focus\n * @dependencies lucide-react\n * @behavior Escape and outside-click both close the popover, resyncing the\n * draft from the last committed value on every open. Without showFooter, any\n * close path commits; with showFooter, only Apply commits and every other\n * close discards the draft.\n * @a11y Trigger is a <button> with aria-expanded and aria-haspopup. The Custom\n * Range selects are native <select> elements, so they keep native keyboard\n * behaviour. Escape closes the popover and discards the draft range.\n * @usage\n * ```tsx\n * <DateRangePicker defaultValue=\"Rolling 6 months\" onChange={setRange} />\n * ```\n */\n\nconst MONTH_ABBR = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\nconst QUARTER_ABBR = ['Q1', 'Q2', 'Q3', 'Q4']\n\n/** What the Custom Range From/To selects pick. */\nexport type DateGranularity = 'month' | 'quarter' | 'year'\nconst PRESETS = ['Rolling 3 months', 'Rolling 6 months', 'Rolling 12 months']\n\nconst startOfToday = () => {\n const d = new Date()\n return new Date(d.getFullYear(), d.getMonth(), d.getDate())\n}\nconst fmtDate = (d: Date) => d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n\n/** Resolve a label to its actual [start, end] span, ending at `today`. */\nexport function resolveRange(label: string, today: Date = startOfToday()): [Date, Date] {\n const end = today\n const mMonths = label.match(/Rolling (\\d+) months/)\n if (mMonths) {\n return [new Date(end.getFullYear(), end.getMonth() - Number(mMonths[1]), 1), end]\n }\n const mQuarters = label.match(/Rolling (\\d+) quarters/)\n if (mQuarters) {\n return [new Date(end.getFullYear(), end.getMonth() - Number(mQuarters[1]) * 3, 1), end]\n }\n const mYears = label.match(/Rolling (\\d+) years/)\n if (mYears) {\n return [new Date(end.getFullYear() - Number(mYears[1]), end.getMonth(), 1), end]\n }\n const mCustom = label.match(/([A-Za-z]{3})\\s+(\\d{4}).*?([A-Za-z]{3})\\s+(\\d{4})/)\n if (mCustom) {\n const s = new Date(Number(mCustom[2]), MONTH_ABBR.indexOf(mCustom[1]), 1)\n const e = new Date(Number(mCustom[4]), MONTH_ABBR.indexOf(mCustom[3]) + 1, 0)\n return [s, e]\n }\n return [new Date(end.getFullYear(), end.getMonth() - 6, 1), end]\n}\n\n/** \"Dec 1, 2025 – Jun 25, 2026\" for a label. */\nfunction spanLabel(label: string, today: Date): string {\n const [s, e] = resolveRange(label, today)\n return `${fmtDate(s)} – ${fmtDate(e)}`\n}\n\nfunction MiniSelect<T extends string | number>({ value, onChange, options }: { value: T; onChange: (v: T) => void; options: { label: string; value: T }[] }) {\n return (\n <select\n value={String(value)}\n onChange={(e) => {\n const opt = options.find((o) => String(o.value) === e.target.value)\n if (opt) onChange(opt.value)\n }}\n className=\"rounded-control border border-border-default bg-input px-1.5 py-1 text-[12px] text-text-primary outline-hidden focus:border-border-focus\"\n >\n {options.map((o) => (\n <option key={String(o.value)} value={String(o.value)}>{o.label}</option>\n ))}\n </select>\n )\n}\n\nexport function DateRangePicker({\n defaultValue = 'Rolling 6 months',\n granularity = 'month',\n align = 'left',\n presets = PRESETS,\n onChange,\n onRangeChange,\n showFooter = false,\n today,\n years,\n}: {\n defaultValue?: string\n align?: 'left' | 'right'\n /**\n * What the Custom Range From/To selects pick. `month` shows month + year\n * selects, `quarter` shows quarter + year, `year` shows year alone -- and\n * the applied label follows suit. Pair it with matching `presets`.\n */\n granularity?: DateGranularity\n /** Rolling presets shown above Custom Range. Defaults to 3/6/12 months. */\n presets?: string[]\n onChange?: (label: string) => void\n /** Reports the resolved start/end dates — used to drive dependent views (e.g. table columns). */\n onRangeChange?: (start: Date, end: Date) => void\n /** Deferred mode: preset/custom-range picks stage in a draft; only the fixed\n * Apply footer commits it (no live commit on click). */\n showFooter?: boolean\n /** End of the available data window: rolling presets resolve back from here.\n * Defaults to the current date. */\n today?: Date\n /** Years offered in the Custom Range selects. Defaults to the last four,\n * ending with `today`'s year. */\n years?: number[]\n}) {\n const end = useMemo(() => today ?? startOfToday(), [today])\n const yearOptions = years ?? [3, 2, 1, 0].map((n) => end.getFullYear() - n)\n const [open, setOpen] = useState(false)\n const [value, setValue] = useState(defaultValue)\n // Draft label staged while the dropdown is open in footer mode — the trigger\n // keeps showing `value` (the committed range) until Apply commits the draft.\n const [draft, setDraft] = useState(defaultValue)\n const ref = useRef<HTMLDivElement>(null)\n // Custom Range opens on the year ending at `today`'s month.\n const [fromMo, setFromMo] = useState(end.getMonth())\n const [fromYr, setFromYr] = useState(end.getFullYear() - 1)\n const [toMo, setToMo] = useState(end.getMonth())\n const [toYr, setToYr] = useState(end.getFullYear())\n const [fromQ, setFromQ] = useState(Math.floor(end.getMonth() / 3))\n const [toQ, setToQ] = useState(Math.floor(end.getMonth() / 3))\n\n // Emit the resolved range on mount and whenever the committed value changes,\n // so range-driven consumers (e.g. Sports month columns) stay in sync.\n useEffect(() => {\n const [s, e] = resolveRange(value, end)\n onRangeChange?.(s, e)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value])\n\n const toggleOpen = () => {\n if (!open) setDraft(value) // resync the draft from the last applied state on every open\n setOpen((o) => !o)\n }\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n const onKey = (e: KeyboardEvent) => e.key === 'Escape' && setOpen(false)\n window.addEventListener('mousedown', onDown)\n window.addEventListener('keydown', onKey)\n return () => { window.removeEventListener('mousedown', onDown); window.removeEventListener('keydown', onKey) }\n }, [open])\n\n const commit = (label: string) => { setValue(label); onChange?.(label); setOpen(false) }\n\n // Span in whole periods at the active granularity -- 1 or more means From\n // isn't past To.\n const span =\n granularity === 'year'\n ? toYr - fromYr + 1\n : granularity === 'quarter'\n ? toYr * 4 + toQ - (fromYr * 4 + fromQ) + 1\n : toYr * 12 + toMo - (fromYr * 12 + fromMo) + 1\n const valid = span >= 1\n const applyCustom = () => {\n if (!valid) return\n const label =\n granularity === 'year'\n ? `${fromYr} – ${toYr}`\n : granularity === 'quarter'\n ? `${QUARTER_ABBR[fromQ]} ${fromYr} – ${QUARTER_ABBR[toQ]} ${toYr}`\n : `${MONTH_ABBR[fromMo]} ${fromYr} – ${MONTH_ABBR[toMo]} ${toYr}`\n if (showFooter) setDraft(label)\n else commit(label)\n }\n\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n onClick={toggleOpen}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n className={chipTriggerClass()}\n >\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] text-text-tertiary\">{spanLabel(value, end)}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n <ChevronDown size={14} aria-hidden=\"true\" className={cn('shrink-0 text-text-secondary transition-transform', open && 'rotate-180')} />\n </button>\n {open && (\n <div className={cn('absolute top-[calc(100%+8px)] z-30 w-[280px] overflow-hidden rounded-card border border-border-default bg-surface py-1 shadow-overlay', align === 'right' ? 'right-0' : 'left-0')}>\n {presets.map((p) => (\n <button\n key={p}\n type=\"button\"\n onClick={() => (showFooter ? setDraft(p) : commit(p))}\n className={cn('block w-full px-3 py-2 text-left text-[13px] transition-colors hover:bg-subtle', (showFooter ? draft : value) === p ? 'font-semibold text-brand-primaryAction' : 'text-text-secondary')}\n >\n {p}\n </button>\n ))}\n <div className=\"mt-1 border-t border-border-default px-3 pb-2 pt-2\">\n <div className=\"text-[13px] font-semibold text-text-primary\">Custom Range</div>\n <div className=\"mt-2 flex flex-col gap-2\">\n <label className=\"flex items-center justify-between gap-2 text-[12px] text-text-secondary\">\n From\n <span className=\"flex gap-1\">\n {granularity === 'month' && (\n <MiniSelect value={fromMo} onChange={setFromMo} options={MONTH_ABBR.map((mm, i) => ({ label: mm, value: i }))} />\n )}\n {granularity === 'quarter' && (\n <MiniSelect value={fromQ} onChange={setFromQ} options={QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i }))} />\n )}\n <MiniSelect value={fromYr} onChange={setFromYr} options={yearOptions.map((y) => ({ label: String(y), value: y }))} />\n </span>\n </label>\n <label className=\"flex items-center justify-between gap-2 text-[12px] text-text-secondary\">\n To\n <span className=\"flex gap-1\">\n {granularity === 'month' && (\n <MiniSelect value={toMo} onChange={setToMo} options={MONTH_ABBR.map((mm, i) => ({ label: mm, value: i }))} />\n )}\n {granularity === 'quarter' && (\n <MiniSelect value={toQ} onChange={setToQ} options={QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i }))} />\n )}\n <MiniSelect value={toYr} onChange={setToYr} options={yearOptions.map((y) => ({ label: String(y), value: y }))} />\n </span>\n </label>\n <button\n type=\"button\"\n onClick={applyCustom}\n disabled={!valid}\n className=\"self-start text-[13px] font-semibold text-brand-primaryAction transition-opacity hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {showFooter ? 'Use custom range' : 'Apply'}\n </button>\n </div>\n </div>\n {showFooter && <FilterDropdownFooter onApply={() => commit(draft)} />}\n </div>\n )}\n </div>\n )\n}\n\nexport type DateRangePickerProps = Parameters<typeof DateRangePicker>[0]\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { ChevronDown, Check, Minus, Search, X } from 'lucide-react'\nimport { cn } from './cn'\nimport { chipTriggerClass, ChipContent, type ChipVariant } from './ChipTrigger'\nimport { FilterDropdownFooter } from './FilterDropdownFooter'\n\nexport interface MultiSelectGroup {\n id: string\n label: string\n children: { id: string; label: string }[]\n}\n\n/**\n * @pattern MultiSelectFilter\n * @description Quick-access multi-select chip — mirrors the DateRangeFilter\n * button shape (two-line caption + value with a chevron) and opens a\n * searchable checkbox popover. Used for the page-level Media Type /\n * Advertiser filters that share state with the filter tray.\n * @tokens rounded-control, rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary, text-text-link, border-border-interactive, bg-brand-primaryAction, bg-input, hover:bg-subtle, hover:text-text-primary, placeholder:text-text-tertiary, text-brand-onprimary\n * @dependencies lucide-react\n * @behavior `variant` picks the trigger's chip stroke: `box` (default, the\n * boxed two-line chip on the default border) or `inline` (same fill,\n * darker stroke, for chips sitting directly on the canvas). Left out of\n * the catalog's variant list deliberately: check-prop-drift can't resolve\n * the imported ChipVariant alias through this component's inline prop\n * type, so such a tag would be unvalidated -- and this exact component\n * has had stale ones stripped before.\n * Same draft/commit-on-close pattern as AdvertiserQuickFilter — the\n * draft resyncs from `selected` every time the tray opens, and (without\n * showFooter) any close path commits it, while showFooter mode requires the\n * Apply button and discards the draft on every other close. `min` enforces a\n * selection floor by silently ignoring any toggle that would drop below it —\n * there's no error state, the click just does nothing. Group parents are\n * tri-state and toggle all of their children in one action.\n * @a11y Trigger is a <button> with aria-expanded; the menu is role=\"dialog\" and\n * Escape closes it. Option rows carry their own checkbox semantics. Focus\n * is not moved into the menu on open, so keyboard users tab into it in DOM\n * order.\n * @usage\n * ```tsx\n * <MultiSelectFilter caption=\"Media\" options={mediaOptions} selected={selected} onChange={setSelected} />\n * ```\n */\nexport function MultiSelectFilter({\n caption,\n options = [],\n groups,\n counts,\n variant = 'box',\n selected,\n onChange,\n allLabel = 'All',\n searchable = false,\n searchPlaceholder,\n align = 'left',\n fullIsAll = false,\n min = 0,\n icon,\n showFooter = false,\n clearValue = [],\n menuWidthClass = 'w-60',\n plainParent = false,\n fullWidth = false,\n}: {\n caption: string\n /**\n * Live option-id -> result count. Supplying it makes the menu faceted:\n * every label gets a \"(n)\" suffix and options with nothing behind them\n * drop out. A selected option is always kept, or there would be no way to\n * undo it.\n */\n counts?: Record<string, number>\n /** Chip stroke for the trigger. See ChipVariant. */\n variant?: ChipVariant\n options?: { id: string; label: string }[]\n /** When provided, renders a nested parent → children tree (selection tracks\n * leaf ids; parents are tri-state and toggle all their children). */\n groups?: MultiSelectGroup[]\n selected: string[]\n onChange: (next: string[]) => void\n allLabel?: string\n searchable?: boolean\n /** Overrides the search box's placeholder. The default derives from the\n * caption, which reads wrong once a caption is singular (\"Search topic\"). */\n searchPlaceholder?: string\n align?: 'left' | 'right'\n /** Treat \"all options selected\" as the unfiltered \"All\" state in the label. */\n fullIsAll?: boolean\n /** Minimum selections that must remain (a toggle that would drop below is ignored). */\n min?: number\n icon?: React.ReactNode\n /** Deferred mode: checkbox edits stage in a draft; only the fixed Apply/Clear\n * All footer commits or discards them (no live commit on close). */\n showFooter?: boolean\n /** What \"Clear all\" resets the draft to — the page's default selection. */\n clearValue?: string[]\n /** Tailwind width class for the dropdown panel (default `w-60`). Widen it when\n * option labels are long and would otherwise wrap. */\n menuWidthClass?: string\n /** Render group parents at normal weight instead of semibold. */\n plainParent?: boolean\n /** Stretch the trigger (and, with `menuWidthClass=\"w-full\"`, the panel) to fill\n * its container — for stacked/full-width form layouts instead of the chip bar. */\n fullWidth?: boolean\n}) {\n // Flat list of selectable leaves — the source of truth for label + \"all\".\n // A childless group (a flat parent, e.g. \"Outdoor\") acts as its own leaf.\n const groupLeaves = (g: MultiSelectGroup) => (g.children.length ? g.children : [{ id: g.id, label: g.label }])\n const leafOptions = groups ? groups.flatMap(groupLeaves) : options\n const [open, setOpen] = useState(false)\n const [q, setQ] = useState('')\n // Draft buffers selections while open; we only commit to onChange on close so\n // the page isn't re-filtered on every toggle.\n const [draft, setDraft] = useState<string[]>(selected)\n const ref = useRef<HTMLDivElement>(null)\n\n // Close commits the draft (if it changed) — single place all close paths funnel through.\n // In footer mode, closing (outside click / Escape / re-click) never commits —\n // only the Apply button does — so the trigger label never previews the draft.\n const close = useCallback(() => {\n setOpen(false)\n setQ('')\n if (showFooter) return\n if (draft.length !== selected.length || draft.some((id) => !selected.includes(id))) {\n onChange(draft)\n }\n }, [draft, selected, onChange, showFooter])\n\n const openTray = () => {\n setDraft(selected) // resync from latest applied state\n setOpen(true)\n }\n\n const apply = () => {\n onChange(draft)\n setOpen(false)\n setQ('')\n }\n\n useEffect(() => {\n if (!open) return\n const onKey = (e: KeyboardEvent) => e.key === 'Escape' && close()\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) close()\n }\n window.addEventListener('keydown', onKey)\n window.addEventListener('mousedown', onClick)\n return () => {\n window.removeEventListener('keydown', onKey)\n window.removeEventListener('mousedown', onClick)\n }\n }, [open, close])\n\n const toggle = (id: string) =>\n setDraft((cur) => {\n const next = cur.includes(id) ? cur.filter((x) => x !== id) : [...cur, id]\n if (next.length < min) return cur // honor minimum (e.g. Media needs ≥1)\n return next\n })\n\n // Parent (group) toggle — selects/deselects all of a group's leaves at once.\n const toggleGroup = (g: MultiSelectGroup) =>\n setDraft((cur) => {\n // Never bulk-select a leaf that has nothing behind it (but always allow\n // deselecting one that's somehow already picked).\n const ids = groupLeaves(g)\n .map((c) => c.id)\n .filter((id) => !counts || (counts[id] ?? 0) > 0 || cur.includes(id))\n if (!ids.length) return cur\n const allSel = ids.every((id) => cur.includes(id))\n const next = allSel ? cur.filter((id) => !ids.includes(id)) : [...new Set([...cur, ...ids])]\n if (next.length < min) return cur\n return next\n })\n\n /** An option is listed only while something is behind it. A selected option\n * is always listed, or there'd be no way to undo it. */\n const isAvailable = (id: string) => !counts || (counts[id] ?? 0) > 0 || draft.includes(id)\n const countFor = (id: string) => counts?.[id] ?? 0\n\n const groupState = (g: MultiSelectGroup): 'none' | 'some' | 'all' => {\n const ids = groupLeaves(g).map((c) => c.id).filter(isAvailable)\n if (!ids.length) return 'none'\n const sel = ids.filter((id) => draft.includes(id)).length\n return sel === 0 ? 'none' : sel === ids.length ? 'all' : 'some'\n }\n\n // The chip reflects the draft while open (live preview) and applied state when\n // closed — except in footer mode, where it always reflects the last applied\n // state so nothing changes until Apply is clicked.\n const shown = open && !showFooter ? draft : selected\n const isAll = shown.length === 0 || (fullIsAll && shown.length === leafOptions.length)\n const value = isAll\n ? allLabel\n : shown.length === 1\n ? leafOptions.find((o) => o.id === shown[0])?.label ?? `${shown.length} selected`\n : `${shown.length} selected`\n\n const ql = q.trim().toLowerCase()\n const items = options.filter((o) => isAvailable(o.id) && (!ql || o.label.toLowerCase().includes(ql)))\n // Grouped search: a group whose label matches keeps all its children; otherwise\n // only its matching children are shown (group hidden when nothing matches).\n const visibleGroups: MultiSelectGroup[] = groups\n ? groups\n .map((g): MultiSelectGroup | null => {\n const live = g.children.filter((c) => isAvailable(c.id))\n if (!live.length && !isAvailable(g.id)) return null\n if (!ql || g.label.toLowerCase().includes(ql)) return { ...g, children: live }\n const kids = live.filter((c) => c.label.toLowerCase().includes(ql))\n return kids.length ? { ...g, children: kids } : null\n })\n .filter((g): g is MultiSelectGroup => g !== null)\n : []\n\n return (\n <div className={cn('relative', fullWidth && 'w-full')} ref={ref}>\n <button\n type=\"button\"\n onClick={() => (open ? close() : openTray())}\n aria-expanded={open}\n className={cn(chipTriggerClass(variant), fullWidth && 'w-full justify-between')}\n >\n <ChipContent caption={caption} value={value} icon={icon} />\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cn('shrink-0 text-text-secondary transition-transform', open && 'rotate-180')}\n />\n </button>\n\n {open && (\n <div\n className={cn(\n 'absolute top-[calc(100%+8px)] z-30 flex flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay',\n menuWidthClass,\n align === 'right' ? 'right-0' : 'left-0'\n )}\n role=\"dialog\"\n aria-label={caption}\n >\n {searchable && (\n <div className=\"border-b border-border-default p-2\">\n <div className=\"flex h-9 items-center gap-2 rounded-control border border-border-default bg-input px-2.5\">\n <Search size={14} className=\"text-text-secondary\" aria-hidden=\"true\" />\n <input\n type=\"text\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={searchPlaceholder ?? `Search ${caption.toLowerCase()}`}\n className=\"h-full flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary\"\n />\n {q && (\n <button type=\"button\" onClick={() => setQ('')} aria-label=\"Clear search\" className=\"text-text-tertiary hover:text-text-primary\">\n <X size={13} />\n </button>\n )}\n </div>\n </div>\n )}\n <div className=\"max-h-[280px] overflow-y-auto p-1\">\n {groups\n ? visibleGroups.map((g) => {\n const state = groupState(g)\n return (\n <div key={g.id}>\n {/* Parent — tri-state; toggles all of its children. */}\n <button\n type=\"button\"\n onClick={() => toggleGroup(g)}\n className=\"flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle\"\n >\n <TriCheck state={state} />\n <span className={cn('flex-1 text-[14px] text-text-primary', !plainParent && 'font-semibold')}>{g.label}</span>\n {counts && <OptionCount n={countFor(g.id)} />}\n </button>\n {/* Children — indented under the parent. */}\n {g.children.map((c) => {\n const checked = draft.includes(c.id)\n return (\n <button\n key={c.id}\n type=\"button\"\n onClick={() => toggle(c.id)}\n className=\"flex w-full items-center gap-2.5 rounded-control py-2 pl-9 pr-2 text-left transition-colors hover:bg-subtle\"\n >\n <TriCheck state={checked ? 'all' : 'none'} />\n <span className=\"flex-1 text-[14px] text-text-primary\">{c.label}</span>\n {counts && <OptionCount n={countFor(c.id)} />}\n </button>\n )\n })}\n </div>\n )\n })\n : items.map((o) => {\n const checked = draft.includes(o.id)\n return (\n <button\n key={o.id}\n type=\"button\"\n onClick={() => toggle(o.id)}\n className=\"flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle\"\n >\n <span\n className={cn(\n 'flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors',\n checked\n ? 'border-transparent bg-brand-primaryAction text-brand-onprimary'\n : 'border-border-interactive bg-input'\n )}\n >\n {checked && <Check size={13} strokeWidth={3} />}\n </span>\n <span className=\"flex-1 text-[14px] text-text-primary\">{o.label}</span>\n {counts && <OptionCount n={countFor(o.id)} />}\n </button>\n )\n })}\n {((groups && !visibleGroups.length) || (!groups && !items.length)) && (\n <div className=\"py-6 text-center text-[13px] text-text-tertiary\">No matches.</div>\n )}\n </div>\n {showFooter ? (\n <FilterDropdownFooter onClear={() => setDraft(clearValue)} onApply={apply} />\n ) : (\n min === 0 && draft.length > 0 && (\n <div className=\"border-t border-border-default p-2\">\n <button\n type=\"button\"\n onClick={() => setDraft([])}\n className=\"text-[12px] font-medium text-text-link hover:underline\"\n >\n Clear {caption.toLowerCase()}\n </button>\n </div>\n )\n )}\n </div>\n )}\n </div>\n )\n}\n\n/** Checkbox visual supporting a tri-state: all (check), some (dash), none (empty). */\nfunction TriCheck({ state }: { state: 'none' | 'some' | 'all' }) {\n const filled = state !== 'none'\n return (\n <span\n className={cn(\n 'flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors',\n filled\n ? 'border-transparent bg-brand-primaryAction text-brand-onprimary'\n : 'border-border-interactive bg-input'\n )}\n >\n {state === 'all' && <Check size={13} strokeWidth={3} />}\n {state === 'some' && <Minus size={13} strokeWidth={3} />}\n </span>\n )\n}\n\nexport type MultiSelectFilterProps = Parameters<typeof MultiSelectFilter>[0]\n\n/** Result count shown after an option label in faceted mode. */\nfunction OptionCount({ n }: { n: number }) {\n return <span className=\"shrink-0 text-[12px] tabular-nums text-text-tertiary\">({n.toLocaleString()})</span>\n}\n","import { cn } from \"./cn\";\n\n/**\n * Track, knob and travel per size. The knob leaves a 2px gutter at each end, so\n * its \"on\" offset is always track − knob − 2 — keep that relationship if a new\n * size is added, or the knob will sit off-centre at one end.\n */\nconst SIZES = {\n sm: { track: \"h-5 w-9\", knob: \"h-4 w-4\", on: \"translate-x-[18px]\" },\n md: { track: \"h-6 w-11\", knob: \"h-5 w-5\", on: \"translate-x-[22px]\" },\n} as const;\n\nexport interface ToggleProps {\n /** Whether the switch is on. Controlled: the parent owns this value. */\n checked: boolean;\n /** Receives the value being switched TO, not the current one. */\n onChange: (next: boolean) => void;\n /** Accessible name; the visible label lives in the row around it. */\n label: string;\n /** `md` for settings rows where the switch is the subject; `sm` for dense rows next to 13px text. */\n size?: keyof typeof SIZES;\n /** Blocks clicks and dims the switch to 50% opacity. */\n disabled?: boolean;\n /** Extra classes merged onto the track (the outer `<button>`). */\n className?: string;\n}\n\n/**\n * @pattern Toggle\n * @description The app's on/off switch. Use it for a setting that takes effect\n * as a state the user keeps — \"only include enriched creatives\", \"email me a\n * digest\" — where a checkbox would read as an item being ticked off a list.\n * Rendered as a `<button role=\"switch\">` so the on/off state is announced as a\n * switch rather than a checkbox, and so the track and knob can carry the brand\n * fill without fighting a native input's styling hooks.\n * @tokens bg-brand-primaryAction, bg-border-interactive, bg-surface, shadow-raised, outline-border-focus\n * @behavior The knob is positioned by `translate-x`, not by flex alignment, so\n * the slide animates. Off uses `bg-border-interactive` rather than a grey\n * literal, which keeps the track visible against `bg-surface` in dark mode.\n * Pair it with a label and any InfoTip in the surrounding row: this component\n * draws only the switch, so rows stay free to lay the label out however they\n * need (usually label left, switch pushed right).\n * @variant md - Settings panels and modals, where the switch is the row's subject.\n * @variant sm - Dense rows next to 13px body text, where the md track overpowers its own label.\n * @a11y The <button> carries role=\"switch\" and aria-checked, so it is the\n * control -- don't nest it in another interactive element. `label`\n * supplies the accessible name; without it the switch is announced\n * unlabelled.\n * @usage\n * ```tsx\n * <Toggle checked={enabled} onChange={setEnabled} label=\"Email news alerts\" />\n * <Toggle size=\"sm\" checked={enabled} onChange={setEnabled} label=\"Only include enriched creatives\" />\n * ```\n */\nexport function Toggle({ checked, onChange, label, size = \"md\", disabled, className }: ToggleProps) {\n const s = SIZES[size];\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-label={label}\n disabled={disabled}\n onClick={() => onChange(!checked)}\n className={cn(\n \"relative inline-flex shrink-0 items-center rounded-full transition-colors focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus\",\n s.track,\n checked ? \"bg-brand-primaryAction\" : \"bg-border-interactive\",\n disabled && \"cursor-not-allowed opacity-50\",\n className\n )}\n >\n <span\n className={cn(\n \"inline-block transform rounded-full bg-surface shadow-raised transition-transform\",\n s.knob,\n checked ? s.on : \"translate-x-0.5\"\n )}\n />\n </button>\n );\n}\n","\"use client\";\n\nimport { useId } from \"react\";\nimport { Sparkles } from \"lucide-react\";\n\nexport interface AISparkProps {\n size?: number;\n className?: string;\n}\n\n/**\n * @pattern AISpark\n * @description Assistant glyph — the lucide Sparkles icon stroked with the\n * MR orange→violet assistant gradient. Each instance scopes its own gradient\n * id, and the stops follow light/dark mode.\n * @dependencies lucide-react\n * @usage\n * ```tsx\n * <AISpark size={14} />\n * ```\n */\nexport function AISpark({ size = 16, className }: AISparkProps) {\n const id = useId();\n return (\n <>\n <svg width=\"0\" height=\"0\" aria-hidden=\"true\" style={{ position: \"absolute\" }}>\n <defs>\n <linearGradient id={id} x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"var(--mr-color-brand-primary)\" />\n {/* The violet end is a literal: @mediaradar/design-tokens has no\n assistant token yet. Same light/dark values as\n insights-studio-prototype's local --color-assistant-to; the dark\n one keys off data-theme, the attribute design-tokens' dark.css uses. */}\n <stop offset=\"100%\" className=\"[stop-color:#9474ff] in-data-[theme=dark]:[stop-color:#a488ff]\" />\n </linearGradient>\n </defs>\n </svg>\n <Sparkles size={size} stroke={`url(#${id})`} className={className} aria-hidden=\"true\" />\n </>\n );\n}\n","import { cn } from \"./cn\";\n\nexport type FreshnessLevel = \"fresh\" | \"recent\" | \"stale\";\n\nconst dotColor: Record<FreshnessLevel, string> = {\n fresh: \"bg-status-success\",\n recent: \"bg-status-warning\",\n stale: \"bg-text-tertiary\",\n};\n\nconst srLabel: Record<FreshnessLevel, string> = {\n fresh: \"Fresh (under 4 hours)\",\n recent: \"Recent (today)\",\n stale: \"Older than a day\",\n};\n\nexport interface FreshnessProps {\n level: FreshnessLevel;\n}\n\n/**\n * @pattern Freshness\n * @description Freshness dot — prefixed to card meta rows so a row of 4\n * timestamps stops reading as a wall of identical text. Color carries the\n * urgency signal at a glance.\n * @tokens bg-status-success, bg-status-warning, bg-text-tertiary\n * @a11y role=\"img\" with an aria-label per level, so the dot has a text\n * alternative rather than announcing as decoration. The label is the only\n * thing a screen reader gets -- the colour carries no meaning on its own.\n * @usage\n * ```tsx\n * <Freshness level=\"fresh\" />\n * ```\n */\nexport function Freshness({ level }: FreshnessProps) {\n return (\n <span\n className={cn(\"inline-block h-1.5 w-1.5 shrink-0 rounded-full\", dotColor[level])}\n role=\"img\"\n aria-label={srLabel[level]}\n />\n );\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","Search","jsx","jsxs","Fragment","jsx","jsxs","useState","useRef","useEffect","Search","jsx","jsxs","jsx","jsxs","Check","jsx","Check","useEffect","useMemo","useRef","useState","ChevronDown","jsx","jsxs","slug","useEffect","useRef","useState","Check","ChevronDown","Search","Fragment","jsx","jsxs","cx","useRef","ChevronLeft","ChevronRight","jsx","jsxs","useEffect","useRef","useState","Check","ChevronDown","jsx","jsxs","cx","useState","useRef","useEffect","ChevronDown","Check","useCallback","useEffect","useRef","useState","createPortal","Check","ChevronDown","jsx","jsxs","cx","slug","jsx","jsxs","Card","jsx","jsxs","useEffect","useRef","useState","ChevronDown","X","jsx","jsxs","cx","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","useEffect","useLayoutEffect","useRef","useState","createPortal","jsx","jsxs","cx","jsx","jsxs","ListChecks","jsx","jsxs","ChevronDown","jsx","jsxs","cx","useCallback","useEffect","useLayoutEffect","useMemo","useRef","useState","createPortal","Search","Info","ChevronRight","ChevronDown","Check","Fragment","jsx","jsxs","cx","slug","useState","useMemo","Search","ChevronRight","Info","Check","useRef","useCallback","useLayoutEffect","useEffect","ChevronDown","createPortal","useState","jsx","jsxs","cx","forwardRef","Loader2","jsx","jsxs","forwardRef","Loader2","jsx","jsxs","useEffect","useState","createPortal","jsx","jsxs","useState","useEffect","createPortal","jsx","jsxs","X","jsx","jsxs","X","jsx","jsxs","ChevronLeft","ChevronRight","jsx","jsxs","ChevronLeft","ChevronRight","jsx","jsx","ChevronDown","ChevronLeft","ChevronRight","jsx","jsxs","ChevronDown","ChevronLeft","ChevronRight","useEffect","useMemo","useRef","useState","ChevronDown","jsx","jsxs","useMemo","useState","useRef","useEffect","ChevronDown","useCallback","useEffect","useRef","useState","ChevronDown","Check","Minus","Search","X","jsx","jsxs","useState","useRef","useCallback","useEffect","ChevronDown","Search","X","Check","Minus","jsx","SIZES","useId","Fragment","jsx","jsxs","jsx"]}
1
+ {"version":3,"sources":["../src/InfoTip.tsx","../src/AdvertiserQuickFilter.tsx","../src/AdvertiserSearchPrompt.tsx","../src/cn.ts","../src/Badge.tsx","../src/Delta.tsx","../src/CheckBox.tsx","../src/DateRangeFilter.tsx","../src/SearchBar.tsx","../src/SectionRail.tsx","../src/DataScopeFilter.tsx","../src/SelectFilter.tsx","../src/Card.tsx","../src/NoResultsEmptyState.tsx","../src/WorkspaceSelectedCard.tsx","../src/chart-placeholder-shared.tsx","../src/BarChartPlaceholder.tsx","../src/LineChartPlaceholder.tsx","../src/PieChartPlaceholder.tsx","../src/StackedColumnPlaceholder.tsx","../src/Tooltip.tsx","../src/AdvertiserNoResults.tsx","../src/SelectAllVisible.tsx","../src/SelectedSection.tsx","../src/SelectionPicker.tsx","../src/PublisherBreakdownList.tsx","../src/Button.tsx","../src/FilterDropdownFooter.tsx","../src/NameListModal.tsx","../src/ChipTrigger.tsx","../src/FilterChipBar.tsx","../src/SortButton.tsx","../src/tableSort.ts","../src/Pager.tsx","../src/WorkspaceAvatar.tsx","../src/Tag.tsx","../src/TablePagination.tsx","../src/DateRangePicker.tsx","../src/MultiSelectFilter.tsx","../src/Toggle.tsx","../src/AISpark.tsx","../src/Freshness.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Info } from \"lucide-react\";\n\n/**\n * @pattern InfoTip\n * @description Info tooltip — a small info glyph that opens a portalled,\n * viewport-clamped bubble. Mirrors the Publisher Intel header affordance so\n * page subtitles can collapse into the eyebrow.\n * @tokens text-text-tertiary, rounded-control, border-border-default, bg-surface,\n * shadow-overlay, text-text-secondary, focus-visible:outline-border-focus,\n * hover:text-text-primary, tracking-normal\n * @dependencies lucide-react\n * @behavior 'click' mode toggles on click only. 'hover' mode also opens on\n * keyboard focus and closes on blur, so it stays reachable without a mouse —\n * not just a decorative hover effect. Both modes close on Escape and on any\n * outside click. The bubble is portaled to document.body and repositions\n * itself to stay clear of the right viewport edge.\n * @a11y The trigger is a <button> reporting aria-expanded; the bubble is\n * role=\"tooltip\" and Escape dismisses it. It describes its anchor rather\n * than naming it, so the anchor still needs its own accessible name.\n * @usage\n * ```tsx\n * <InfoTip text=\"Trims time periods to data that has finalized across the selected media formats.\" />\n * <InfoTip text=\"Hover variant\" trigger=\"hover\" />\n * ```\n */\nexport interface InfoTipProps {\n /** The bubble's content. */\n text: string;\n /** Glyph size in pixels. */\n size?: number;\n /** Accessible label for the trigger button. */\n label?: string;\n /**\n * 'click' toggles the bubble (default); 'hover' reveals it on hover, and\n * also on keyboard focus so it stays reachable without a pointer.\n */\n trigger?: \"click\" | \"hover\";\n}\n\nexport function InfoTip({ text, size = 11, label = \"More information\", trigger = \"click\" }: InfoTipProps) {\n const [open, setOpen] = useState(false);\n const [pos, setPos] = useState<{ top: number; left: number; width: number } | null>(null);\n const btnRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n if (!btnRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n window.addEventListener(\"mousedown\", onDown);\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"mousedown\", onDown);\n window.removeEventListener(\"keydown\", onKey);\n };\n }, [open]);\n\n // Position the bubble under the glyph, clamped within the viewport so it\n // never squeezes against the right edge.\n const place = () => {\n if (!btnRef.current) return;\n const r = btnRef.current.getBoundingClientRect();\n const width = Math.min(260, window.innerWidth - 24);\n const left = Math.max(12, Math.min(r.left, window.innerWidth - width - 12));\n setPos({ top: r.bottom + 6, left, width });\n };\n\n const show = () => {\n place();\n setOpen(true);\n };\n\n const toggle = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!open) show();\n else setOpen(false);\n };\n\n // Hover trigger also opens on keyboard focus so it stays reachable.\n const hoverProps =\n trigger === \"hover\"\n ? {\n onMouseEnter: show,\n onMouseLeave: () => setOpen(false),\n onFocus: show,\n onBlur: () => setOpen(false),\n }\n : {};\n\n return (\n <>\n <button\n ref={btnRef}\n type=\"button\"\n onClick={toggle}\n aria-label={label}\n aria-expanded={open}\n {...hoverProps}\n className=\"inline-flex cursor-pointer items-center text-text-tertiary transition-colors hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n <Info size={size} aria-hidden=\"true\" />\n </button>\n {open &&\n pos &&\n createPortal(\n <div\n role=\"tooltip\"\n style={{ position: \"fixed\", top: pos.top, left: pos.left, width: pos.width }}\n // z-[90]: deliberately an arbitrary value, not @mediaradar/design-tokens'\n // semantic z-tooltip (1200) -- checked directly: mr-clientapps-insights-\n // studio's real toast layer is a literal z-[100] (ToastProvider.tsx),\n // completely unrelated in scale to design-tokens' 1000+ semantic z-index\n // tokens (z-dropdown/z-modal/z-tooltip). Using the shared token here\n // would render this bubble ABOVE that app's toasts -- the opposite of\n // the original intent (a tooltip should never cover a notification).\n // 90 sits above mr-clientapps' modals (below its own z-[100] toasts) as\n // of this writing -- portals to document.body, becoming a sibling of any\n // open dialog rather than a child of it, so a lower z-index would render\n // invisibly behind the dialog that triggered it. RE-VERIFY this number\n // against any NEW consuming app's own z-index scale before trusting it;\n // this is a leaf component making an assumption about global stacking\n // context it can't fully see.\n className=\"z-[90] rounded-control border border-border-default bg-surface px-3 py-2 text-[12px] font-normal not-italic normal-case leading-relaxed tracking-normal text-text-secondary shadow-overlay\"\n >\n {text}\n </div>,\n document.body\n )}\n </>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Check, ChevronDown, ListChecks, Search, X } from \"lucide-react\";\nimport { AdvertiserSearchPrompt } from \"./AdvertiserSearchPrompt\";\n\n/** Joins truthy class fragments -- a local stand-in so this package doesn't\n * pull in a classnames dependency for one conditional class. */\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/** Above this many visible results, offer a \"select all visible\" shortcut. */\nconst SELECT_ALL_THRESHOLD = 5;\n\n/**\n * @pattern AdvertiserQuickFilter\n * @description Search-first quick filter. Mirrors the standard filter-chip\n * shape (two-line caption + value + chevron) but never preloads the option\n * list -- users must search first, since the advertiser pool is effectively\n * endless. Selections are pinned in a \"Selected (n)\" section at the top so\n * they're never lost when the user runs another search. Named for its\n * original (and still primary) use, but the copy props make it reusable for\n * any dimension that's also search-first in its own filter tray, so the\n * dimension reads the same in the quick bar as it does there.\n * @tokens rounded-control, rounded-card, border-border-default, border-border-strong,\n * border-border-interactive, border-border-focus, bg-surface, bg-input,\n * shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary,\n * text-text-link, bg-brand-primaryAction, text-brand-onprimary,\n * hover:bg-subtle, hover:text-text-primary, placeholder:text-text-tertiary\n * @dependencies lucide-react\n * @behavior The search input auto-focuses the moment the tray opens.\n * Selections buffer in a local draft while open. Without `showFooter`,\n * closing by any means (outside click, Escape, re-click) commits the draft\n * to `onChange`. With `showFooter`, only the Apply button commits -- every\n * other close path discards the draft, so the trigger label never previews\n * an unapplied change. The pinned \"selected\" section persists across\n * searches and collapses when the search is cleared.\n * @a11y Trigger is a <button> with aria-expanded and aria-haspopup; the menu is\n * role=\"dialog\", closed on Escape. Option rows are role=\"checkbox\" with\n * aria-checked, so each row is itself the control -- don't wrap them in\n * another clickable element.\n * @usage\n * ```tsx\n * <AdvertiserQuickFilter options={advertisers} selected={selected} onChange={setSelected} />\n * <AdvertiserQuickFilter options={advertisers} selected={selected} onChange={setSelected} showFooter clearValue={defaults} />\n * ```\n */\nexport interface AdvertiserQuickFilterProps {\n /** Small uppercase label above the value. */\n caption?: string;\n options: { id: string; label: string }[];\n selected: string[];\n onChange: (next: string[]) => void;\n align?: \"left\" | \"right\";\n /** Optional leading icon rendered before the caption/value stack. */\n icon?: React.ReactNode;\n /**\n * Deferred mode: checkbox edits stage in a draft; only the fixed\n * Apply/Clear All footer commits or discards them (no live commit on\n * close). Defaults to false -- live commit-on-close -- so an existing\n * caller's behavior never changes just by picking up a new version of\n * this component.\n */\n showFooter?: boolean;\n /** What \"Clear all\" resets the draft to in footer mode (the page's\n * default selection). */\n clearValue?: string[];\n /** Selected ids the active workspace can't resolve. They stay in the\n * selection -- still committed back, still removable -- but they narrow\n * nothing, so the trigger label leaves them out of the count. */\n parked?: string[];\n /** Search box placeholder. Override alongside the other copy props when\n * the filter isn't advertisers, so the empty and no-results states name\n * the right dimension. */\n searchPlaceholder?: string;\n /** Completes \"Start typing … to filter.\" in the pre-search prompt. */\n promptLabel?: string;\n /** The actionable next step under a no-results message. */\n noResultsHint?: string;\n /** The clear link in footerless mode (unused when `showFooter` is set). */\n clearLabel?: string;\n /**\n * Optional prefix for `data-testid` attributes on the trigger, popover,\n * search input, selected-section toggle, select-all-visible row, each\n * option row (`${testIdPrefix}-option-<slugified-id>`), and the\n * Apply/Clear All footer. Omit entirely for no test-id wiring at all --\n * added specifically so an existing Playwright suite keyed off these ids\n * (mr-clientapps' `AdvertisersPicker`) doesn't lose its locators when\n * swapped over to this shared component.\n */\n testIdPrefix?: string;\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens, trims edge hyphens --\n * matches mr-clientapps' own slug() used to build option test ids. */\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\");\n}\n\nexport function AdvertiserQuickFilter({\n caption = \"Advertiser\",\n options,\n selected,\n onChange,\n align = \"left\",\n icon,\n showFooter = false,\n clearValue = [],\n parked = [],\n searchPlaceholder = \"Search for an advertiser\",\n promptLabel = \"an advertiser name\",\n noResultsHint = \"Try checking your spelling or searching for a broader brand name.\",\n clearLabel = \"Clear advertisers\",\n testIdPrefix,\n}: AdvertiserQuickFilterProps) {\n const [open, setOpen] = useState(false);\n const [q, setQ] = useState(\"\");\n // Draft buffers selections while open; committed to onChange on close (see\n // `showFooter`) so the page isn't re-filtered on every toggle.\n const [draft, setDraft] = useState<string[]>(selected);\n // Selected section starts expanded; clearing the search collapses it so\n // the empty prompt reads cleanly, just like the first open.\n const [selectedOpen, setSelectedOpen] = useState(true);\n const ref = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const clearSearch = () => {\n setQ(\"\");\n setSelectedOpen(false);\n };\n\n // In footer mode, closing (outside click / Escape / re-click) never\n // commits -- only the Apply button does -- so the trigger label never\n // previews the draft. The draft itself is discarded implicitly: the next\n // openTray() re-seeds it from `selected`.\n const close = useCallback(() => {\n setOpen(false);\n setQ(\"\");\n if (showFooter) return;\n if (draft.length !== selected.length || draft.some((id) => !selected.includes(id))) {\n onChange(draft);\n }\n }, [draft, selected, onChange, showFooter]);\n\n const openTray = () => {\n setDraft(selected);\n setSelectedOpen(true);\n setOpen(true);\n };\n\n const apply = () => {\n onChange(draft);\n setOpen(false);\n setQ(\"\");\n };\n\n useEffect(() => {\n if (!open) return;\n inputRef.current?.focus();\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && close();\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n };\n }, [open, close]);\n\n const toggle = (id: string) =>\n setDraft((cur) => (cur.includes(id) ? cur.filter((x) => x !== id) : [...cur, id]));\n\n const ql = q.trim().toLowerCase();\n // Selected rows are pinned and persist regardless of the query.\n const selectedOptions = useMemo(\n () => draft.map((id) => options.find((o) => o.id === id)).filter(Boolean) as { id: string; label: string }[],\n [draft, options]\n );\n // Results exclude what's already selected (those live in the pinned section).\n const results = useMemo(\n () => (ql ? options.filter((o) => !draft.includes(o.id) && o.label.toLowerCase().includes(ql)) : []),\n [ql, options, draft]\n );\n\n const visibleIds = results.map((o) => o.id);\n const allVisibleSelected = visibleIds.length > 0 && visibleIds.every((id) => draft.includes(id));\n const toggleAllVisible = () =>\n setDraft((cur) =>\n allVisibleSelected ? cur.filter((id) => !visibleIds.includes(id)) : [...new Set([...cur, ...visibleIds])]\n );\n\n const shown = open && !showFooter ? draft : selected;\n // Parked ids are held, not applied, so the label counts only what's narrowing.\n const counted = parked.length ? shown.filter((id) => !parked.includes(id)) : shown;\n const value =\n counted.length === 0\n ? \"All\"\n : counted.length === 1\n ? options.find((o) => o.id === counted[0])?.label ?? \"1 selected\"\n : `${counted.length} selected`;\n\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-trigger`}\n onClick={() => (open ? close() : openTray())}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n className=\"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n {icon && <span className=\"shrink-0 text-text-tertiary\">{icon}</span>}\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">{caption}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div\n className={cx(\n \"absolute top-[calc(100%+8px)] z-30 flex w-72 flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay\",\n align === \"right\" ? \"right-0\" : \"left-0\"\n )}\n role=\"dialog\"\n aria-label={caption}\n data-testid={testIdPrefix && `${testIdPrefix}-popover`}\n >\n <div className=\"border-b border-border-default p-2\">\n <div className=\"flex h-9 items-center gap-2 rounded-control border border-border-default bg-input px-2.5 focus-within:border-border-focus focus-within:ring-2 focus-within:ring-border-focus/30\">\n <Search size={14} className=\"shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onMouseDown={() => setSelectedOpen(false)}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n data-testid={testIdPrefix && `${testIdPrefix}-search`}\n className=\"h-full min-w-0 flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary\"\n />\n {q && (\n <button\n type=\"button\"\n onClick={clearSearch}\n aria-label=\"Clear search\"\n className=\"shrink-0 text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <X size={13} />\n </button>\n )}\n </div>\n </div>\n\n <div className=\"max-h-[300px] overflow-y-auto p-1\">\n {/* Pinned selected -- persists across searches so it's never lost. */}\n {selectedOptions.length > 0 && (\n <div className=\"mb-1 border-b border-border-default pb-1\">\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-selected-toggle`}\n onClick={() => setSelectedOpen((v) => !v)}\n aria-expanded={selectedOpen}\n className=\"flex w-full items-center gap-1.5 rounded-control px-2 py-1 text-left text-[11px] font-semibold uppercase tracking-wide text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <ChevronDown\n size={13}\n aria-hidden=\"true\"\n className={cx(\"transition-transform\", !selectedOpen && \"-rotate-90\")}\n />\n Selected ({selectedOptions.length})\n </button>\n {selectedOpen && (\n <div className=\"flex flex-col gap-0.5\">\n {selectedOptions.map((o) => (\n <OptionRow\n key={o.id}\n label={o.label}\n checked\n onToggle={() => toggle(o.id)}\n testId={testIdPrefix && `${testIdPrefix}-option-${slug(o.id)}`}\n />\n ))}\n </div>\n )}\n </div>\n )}\n\n {!ql ? (\n <AdvertiserSearchPrompt label={promptLabel} />\n ) : results.length === 0 ? (\n <div className=\"flex flex-col items-center gap-1.5 px-4 py-8 text-center\">\n <p className=\"text-[13px] font-medium text-text-primary\">No results found for &ldquo;{q.trim()}&rdquo;</p>\n <p className=\"text-[12px] leading-snug text-text-tertiary\">{noResultsHint}</p>\n </div>\n ) : (\n <>\n {results.length > SELECT_ALL_THRESHOLD && (\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-select-all-visible`}\n onClick={toggleAllVisible}\n className=\"flex w-full items-center gap-2 rounded-control px-2 py-1.5 text-left text-[12px] font-semibold text-text-link transition-colors hover:bg-subtle\"\n >\n <ListChecks size={14} aria-hidden=\"true\" />\n {allVisibleSelected ? `Deselect ${results.length} visible` : `Select all ${results.length} visible`}\n </button>\n )}\n {results.map((o) => (\n <OptionRow\n key={o.id}\n label={o.label}\n checked={false}\n onToggle={() => toggle(o.id)}\n testId={testIdPrefix && `${testIdPrefix}-option-${slug(o.id)}`}\n />\n ))}\n </>\n )}\n </div>\n\n {showFooter ? (\n <div className=\"flex items-center justify-between border-t border-border-default px-3 py-2.5\">\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-clear-all`}\n onClick={() => setDraft(clearValue)}\n disabled={draft.length === 0}\n className=\"text-[13px] font-medium text-text-secondary transition-colors hover:text-text-primary disabled:opacity-40\"\n >\n Clear all\n </button>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-apply`}\n onClick={apply}\n className=\"rounded-control bg-brand-primaryAction px-5 py-2 text-[13px] font-semibold text-brand-onprimary transition hover:brightness-110\"\n >\n Apply\n </button>\n </div>\n ) : (\n draft.length > 0 && (\n <div className=\"flex items-center justify-between border-t border-border-default p-2\">\n <span className=\"text-[11px] text-text-tertiary\">{draft.length} selected</span>\n <button\n type=\"button\"\n onClick={() => setDraft([])}\n className=\"text-[12px] font-medium text-text-link hover:underline\"\n >\n {clearLabel}\n </button>\n </div>\n )\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction OptionRow({\n label,\n checked,\n onToggle,\n testId,\n}: {\n label: string;\n checked: boolean;\n onToggle: () => void;\n testId?: string;\n}) {\n return (\n <div\n onClick={onToggle}\n className=\"flex cursor-pointer items-center gap-2.5 rounded-control px-2 py-2 transition-colors hover:bg-subtle\"\n >\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={checked}\n aria-label={label}\n data-testid={testId}\n onClick={(e) => {\n e.stopPropagation();\n onToggle();\n }}\n className={cx(\n \"flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors\",\n \"focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n checked\n ? \"border-transparent bg-brand-primaryAction text-brand-onprimary\"\n : \"border-border-interactive bg-surface hover:border-brand-primaryAction\"\n )}\n >\n {checked && <Check size={13} strokeWidth={3} />}\n </button>\n <span className=\"flex-1 text-[14px] text-text-primary\">{label}</span>\n </div>\n );\n}\n","import { Search } from \"lucide-react\";\n\n/**\n * @pattern AdvertiserSearchPrompt\n * @description Pre-search empty state for a search-first picker — shown the\n * moment the tray opens, before anything has been typed. Used for option\n * pools too large to preload (the advertiser list is effectively endless),\n * where the caller must search before any options can be listed at all.\n * Named for its original (and still primary) use, but the `label` prop makes\n * it reusable for any other search-first dimension (a league picker, say).\n * @tokens bg-subtle, text-text-tertiary\n * @dependencies lucide-react\n * @usage\n * ```tsx\n * <AdvertiserSearchPrompt />\n * <AdvertiserSearchPrompt label=\"a league name\" />\n * ```\n */\nexport interface AdvertiserSearchPromptProps {\n /** Completes \"Start typing … to filter.\" */\n label?: string;\n}\n\nexport function AdvertiserSearchPrompt({ label = \"an advertiser name\" }: AdvertiserSearchPromptProps) {\n return (\n <div className=\"flex flex-col items-center gap-2 px-4 py-8 text-center\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-subtle text-text-tertiary\">\n <Search size={16} aria-hidden=\"true\" />\n </span>\n <p className=\"text-[12px] leading-snug text-text-tertiary\">Start typing {label} to filter.</p>\n </div>\n );\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\n/**\n * tailwind-merge, taught about this design system's own font-size steps.\n *\n * Without this, `text-micro` and `text-dense` are silently DELETED. Both look\n * like text-colour classes to tailwind-merge -- it has no way to know `micro`\n * is a size and `secondary` is a colour -- so a component doing\n * `cn(\"text-micro\", \"text-text-secondary\")` ends up with only the colour, and\n * the badge renders at the inherited 16px instead of 10px.\n *\n * It fails silently and only in components that set a size AND a colour\n * through cn(), which is most of them. Found by measuring a rendered badge,\n * not by any build error: the class is present in the source, present in the\n * bundle, and simply absent from the DOM.\n *\n * Any future custom font-size token has to be added here too.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n \"font-size\": [{ text: [\"micro\", \"dense\"] }],\n },\n },\n});\n\n// The tailwind-merge step is what lets a caller's className override a\n// component's own class for the same property (e.g. <Button className=\"px-2\">);\n// a plain join would keep both.\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"./cn\";\n\n/**\n * Fill and ink. `tone` answers \"what kind of thing is this\", never \"what\n * colour do I want\" -- a caller reaching for `danger` because red looks good\n * is the start of the drift this component replaces.\n */\nexport type BadgeTone =\n | \"neutral\"\n | \"brand\"\n | \"brandSolid\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"ai\"\n | \"overlay\";\n\n/**\n * Shape and case. Orthogonal to tone: any tone can be any kind, which is what\n * keeps this two small props instead of one list of every combination the\n * product happens to use today.\n */\nexport type BadgeKind = \"label\" | \"count\" | \"eyebrow\";\n\nconst TONE: Record<BadgeTone, string> = {\n neutral: \"bg-subtle text-text-secondary\",\n brand: \"bg-brand-primarySoft text-brand-primaryAction\",\n // Solid, not a tint. A filter count's whole job is to be noticed -- it is\n // what tells you the view you are looking at is filtered at all -- so it\n // carries the full brand fill rather than the soft wash `brand` uses for a\n // label like \"Primary\". Missed in the first pass, which collapsed both into\n // one tone; the swap onto real call sites is what surfaced it.\n brandSolid: \"bg-brand-primaryAction text-brand-onprimary\",\n success: \"bg-status-success/15 text-text-success\",\n // Heavier tint than success and danger on purpose. Equal opacity does not\n // give equal presence: the warning amber (#b8843a) sits far closer to the\n // warm canvas than red or green do, so the same 15% that reads clearly for\n // those two disappeared here and the badge looked neutral.\n warning: \"bg-status-warning/30 text-text-warning\",\n danger: \"bg-status-danger/15 text-text-danger\",\n // The gradient is the OUTLINE, not the fill. As a fill it was the most\n // distinct tone by a mile, but white text on it ran from 7.5:1 at the blue\n // end down to 2.1:1 at the amber end -- the last third of every AI badge\n // was unreadable. Outlining keeps the gradient as the signal and puts the\n // text back on a flat tint.\n //\n // Two backgrounds in one box: the tint clipped to the padding box, the\n // gradient to the border box, over a transparent 1px border. The tint is\n // opaque on purpose -- an outline over a transparent centre would let the\n // gradient show through the middle, and the badge has to sit on both the\n // canvas and a card without knowing which.\n ai: \"border border-transparent text-ai-ontint\",\n // Sits on artwork, not on the canvas, so it carries its own scrim rather\n // than a theme surface -- the image behind it is not a colour we control.\n overlay: \"bg-scrim text-brand-onprimary\",\n};\n\n// The gradient outline needs two stacked backgrounds -- the tint clipped to\n// the padding box, the gradient to the border box -- which is a poor fit for\n// a utility class: as an arbitrary value it is an unreadable single token, and\n// its commas collide with the comma-separated @tokens contract the drift check\n// reads. A style object says the same thing legibly and keeps every class in\n// TONE a real, checkable one.\nconst TONE_STYLE: Partial<Record<BadgeTone, CSSProperties>> = {\n ai: {\n background:\n \"linear-gradient(var(--mr-color-ai-tint), var(--mr-color-ai-tint)) padding-box, \" +\n \"var(--mr-color-ai-gradient) border-box\",\n },\n};\n\nconst KIND: Record<BadgeKind, string> = {\n // Twice the vertical room the first version had. At py-0.5 the pill hugged\n // its text and read as a tight little tag; at py-1 it reads as a deliberate\n // object. Taken from the status pills the product had already arrived at by\n // hand, which were noticeably more comfortable than anything else -- the\n // breathing room was what made them so, not their extra pixel of type.\n label: \"px-2.5 py-1\",\n // Square-ish and centred, with a floor width so a 1-digit and a 3-digit\n // count are the same shape, and lining figures so the width does not shift\n // as the number changes.\n count: \"h-[18px] min-w-[18px] justify-center px-1.5 tabular-nums\",\n // The only kind that shouts. Caps need the letterspacing -- caps set tight\n // are harder to read than the sentence case they replaced.\n eyebrow: \"px-2.5 py-1 uppercase tracking-wider\",\n};\n\ninterface BadgeProps {\n /** What kind of thing this marks. Not a colour choice. */\n tone?: BadgeTone;\n /** Shape and case. `count` for a number, `eyebrow` for a category label. */\n kind?: BadgeKind;\n /**\n * Draws a small filled dot before the label, in the tone's own ink. For a\n * status that is scanned down a column rather than read -- the dot is what\n * the eye follows, and it carries the colour at a size the text cannot.\n * Purely decorative: the label is the accessible content, so the dot is\n * hidden from assistive tech rather than announced as a second thing.\n */\n dot?: boolean;\n /** Text, or an icon plus text. Keep it to a few words -- a badge annotates, it does not explain. */\n children: ReactNode;\n className?: string;\n}\n\n/**\n * @pattern Badge\n * @description The one small label that annotates something else: a count on\n * a filter, a status, a category, an AI marker, a flag over artwork. Two\n * props -- `tone` (what kind of thing) and `kind` (shape and case) -- which\n * between them cover every badge treatment in the product.\n * @props\n * tone?: 'neutral' | 'brand' | 'brandSolid' | 'success' | 'warning' | 'danger' | 'ai' | 'overlay' (default 'neutral')\n * kind?: 'label' | 'count' | 'eyebrow' (default 'label')\n * dot?: boolean (default false) -- a filled dot before the label, in the tone's ink\n * children: ReactNode\n * @tokens text-micro, rounded-full, bg-current, bg-subtle, bg-brand-primarySoft, bg-brand-primaryAction,\n * bg-status-success/15, bg-status-warning/30, bg-status-danger/15, bg-scrim,\n * text-text-secondary, text-brand-primaryAction, text-text-success,\n * text-text-warning, text-text-danger, text-ai-ontint, text-brand-onprimary,\n * border-transparent\n * @behavior Not interactive and carries no role: a badge is a label on\n * something else, so it is read as part of that thing rather than announced\n * separately. Anything clickable is a Button or a filter chip, not a Badge.\n * Every badge is one size -- the `micro` step (11px) -- because a badge\n * that competes with the content it annotates has stopped being a badge.\n * @variant neutral - Default. A category, a count of something unremarkable, a quiet flag.\n * @variant brand - This item is special in a way the product cares about -- primary, selected, yours.\n * @variant brandSolid - Full brand fill, for a count that has to be noticed: active filters, unread, selected.\n * @variant success - A finished or healthy state. Never just \"green because it is good news\".\n * @variant warning - Needs attention but is not broken. Partial data, an approaching limit.\n * @variant danger - Failed, expired, or over a hard limit. Not merely \"important\".\n * @variant ai - Generated or AI-assisted content, so the reader knows where it came from.\n * @variant overlay - Sits on top of an image or video still, where no theme surface exists behind it.\n * @use when you need to annotate something else -- a status on a row, a count\n * on a filter tab, a category on a card, a flag over a thumbnail.\n * @use when the label is a few words at most and the reader does not need to\n * act on it.\n * @avoid when the thing is clickable -- use Button, or a filter chip. A badge\n * has no role, no focus state and no hit target, so making one clickable\n * hides the action from keyboard and screen-reader users entirely.\n * @avoid when the text is a sentence, or needs to wrap. A badge that wraps\n * has become a callout; use one.\n * @avoid when you are choosing the tone by colour rather than by meaning. A\n * red badge that does not mean failure teaches readers to ignore red.\n * @avoid when several sit in a row and all say something different -- that is\n * a definition list wearing badges, and reads as noise.\n * @usage\n * ```tsx\n * <Badge>Financial Services</Badge>\n * <Badge tone=\"brandSolid\" kind=\"count\">{activeFilters}</Badge>\n * <Badge tone=\"warning\">Partial month</Badge>\n * <Badge tone=\"success\" dot>Completed</Badge>\n * <Badge kind=\"eyebrow\" tone=\"neutral\">Saved view</Badge>\n * <Badge tone=\"brand\"><Check size={11} aria-hidden=\"true\" />Primary</Badge>\n * ```\n */\nexport function Badge({ tone = \"neutral\", kind = \"label\", dot = false, children, className }: BadgeProps) {\n return (\n <span\n style={TONE_STYLE[tone]}\n className={cn(\n // `inline-flex` + `gap` so a leading icon sits on the text baseline\n // without every caller re-inventing the spacing. `shrink-0` because a\n // badge is almost always beside flexible text that would otherwise\n // squash it. `whitespace-nowrap` because a wrapped badge is a bug.\n \"inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full text-micro font-semibold leading-none\",\n TONE[tone],\n KIND[kind],\n className\n )}\n >\n {dot && <span aria-hidden=\"true\" className=\"size-1.5 shrink-0 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\nexport type { BadgeProps };\n","import { ArrowDownRight, ArrowUpRight } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\ninterface DeltaProps {\n /** The change itself. Its sign picks the direction; render the absolute value. */\n value: number;\n /** What the number is in -- \"%\" for a percentage, \"pts\" for share points. */\n suffix?: string;\n /**\n * Adds a direction arrow before the number. For a column of deltas scanned\n * rather than read, where the arrow is what the eye follows. A single delta\n * beside a figure does not need one -- the sign already says which way.\n */\n arrow?: boolean;\n /** Appended after the suffix, e.g. \"YoY\". Keep it to one or two words. */\n period?: string;\n className?: string;\n}\n\n/**\n * @pattern Delta\n * @description A change over time -- the +6.2% / -2.1% beside a figure. Green\n * up, red down, always with an explicit sign.\n * @props\n * value: number -- sign picks the direction\n * suffix?: string -- \"%\" or \"pts\"\n * arrow?: boolean (default false) -- direction arrow, for a column scanned rather than read\n * period?: string -- e.g. \"YoY\"\n * @tokens text-text-success, text-text-danger\n * @dependencies lucide-react\n * @behavior Takes the type size of whatever contains it rather than setting\n * its own, because it is inline text inside a table cell or a card rather\n * than a box of its own -- a fixed size would fight the density its table\n * already chose.\n * @a11y The sign is the point: colour alone cannot carry direction, for\n * anyone who cannot distinguish the two and for anyone reading it printed or\n * in greyscale. `+` and `-` are always rendered, so the colour is\n * reinforcement rather than the only signal. The arrow is decorative and\n * hidden, since the sign beside it already says the same thing.\n * @use when showing a change against a previous period beside the figure it\n * relates to.\n * @use with `arrow` when deltas run down a column and the reader is scanning\n * for the ones that moved.\n * @avoid when the number is not a change -- a share, a total or a rate is\n * just a number, and colouring it green or red tells the reader something\n * untrue about it.\n * @avoid when up is not good. Green-for-up reads as green-for-better, so a\n * rising cost or a rising error rate needs its own treatment rather than this\n * one inverted, which nobody will notice.\n * @usage\n * ```tsx\n * <Delta value={6.2} suffix=\"%\" />\n * <Delta value={-2.1} suffix=\"%\" period=\"YoY\" />\n * <Delta value={1.4} suffix=\"pts\" arrow />\n * ```\n */\nexport function Delta({ value, suffix = \"%\", arrow = false, period, className }: DeltaProps) {\n const up = value >= 0;\n return (\n <span\n className={cn(\n \"inline-flex items-center gap-0.5 font-medium tabular-nums\",\n up ? \"text-text-success\" : \"text-text-danger\",\n className\n )}\n >\n {arrow &&\n (up ? (\n <ArrowUpRight size={13} aria-hidden=\"true\" />\n ) : (\n <ArrowDownRight size={13} aria-hidden=\"true\" />\n ))}\n {/* A true minus sign, not a hyphen: it matches the plus in width and\n sits on the same optical centre, so a column of deltas stays aligned. */}\n {up ? \"+\" : \"−\"}\n {Math.abs(value).toFixed(1)}\n {suffix}\n {period && <span className=\"ml-0.5\">{period}</span>}\n </span>\n );\n}\n\nexport type { DeltaProps };\n","\"use client\";\n\nimport { Check, Minus } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\n/** Shared box geometry and fill. `CheckBox` and `CheckBoxBox` must never drift\n * apart, so both render through this. */\nfunction boxClass(on: boolean, disabled?: boolean) {\n return cn(\n \"flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors\",\n on ? \"border-transparent bg-brand-primaryAction text-white\" : \"border-border-interactive bg-input\",\n disabled && \"cursor-not-allowed opacity-50\"\n );\n}\n\n/** The check / dash glyph. Nothing is drawn in the unchecked state. */\nfunction Glyph({ checked, indeterminate }: { checked: boolean; indeterminate?: boolean }) {\n if (indeterminate) return <Minus size={13} strokeWidth={3} />;\n return checked ? <Check size={13} strokeWidth={3} /> : null;\n}\n\n/**\n * @pattern CheckBox\n * @description Tri-state checkbox rendered as a `<button>` (not a native\n * `<input type=\"checkbox\">`), so it can carry an indeterminate \"some but not\n * all\" state without the native element's limited styling hooks. Designed to\n * be dropped into a row that already has its own click-to-toggle handler\n * (a common list/table pattern) without double-firing. Where the row itself\n * is the control, use `CheckBoxBox` instead.\n * @tokens bg-brand-primaryAction, border-border-interactive, bg-input,\n * hover:border-brand-primaryAction, focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior `aria-checked` is `\"mixed\"` when indeterminate, otherwise the\n * plain boolean. Indeterminate renders a dash (Minus) instead of a\n * checkmark; checked renders a checkmark; neither renders nothing. The\n * unchecked state previews the brand action color on hover, matching the\n * color the box fills with once checked -- the hover state is a preview of\n * the click's effect, not an unrelated highlight. `onClick` calls\n * `stopPropagation` before firing `onChange` by default, so nesting this\n * inside a row that toggles on its own click can't fire the toggle twice;\n * pass `stopPropagation={false}` where the row should also see the click.\n * @a11y The <button> itself carries role=\"checkbox\" and aria-checked (\"mixed\"\n * when indeterminate), so it IS the control -- never nest it inside\n * another button or a row that is itself clickable. `ariaLabel` is\n * required because the box renders no text. Where the whole row should be\n * the control, use CheckBoxBox inside your own <button role=\"checkbox\">\n * instead: a <button> inside a <button> is invalid markup, and a <div\n * onClick> wrapper is not keyboard-reachable at all.\n * @usage\n * ```tsx\n * <CheckBox checked={selected} ariaLabel=\"Select row\" onChange={toggle} />\n * <CheckBox checked={allSelected} indeterminate={someSelected} ariaLabel=\"Select all\" onChange={toggleAll} />\n * <CheckBox checked={false} disabled ariaLabel=\"Select row\" title=\"Max 5 rows -- remove one first\" onChange={toggle} />\n * ```\n */\nexport interface CheckBoxProps {\n /** Whether the box is checked. Controlled: the parent owns this value. */\n checked: boolean;\n /**\n * Some-but-not-all state for a \"select all\" checkbox -- shows a dash\n * instead of a check, and reports `aria-checked=\"mixed\"` instead of the\n * plain boolean.\n */\n indeterminate?: boolean;\n /**\n * Called on click with no argument -- flip `checked` yourself. By default\n * the click doesn't bubble, so a row that toggles on its own click won't\n * fire twice.\n */\n onChange: () => void;\n /** Accessible label -- required since the control carries no visible text of its own. */\n ariaLabel: string;\n /** Blocks clicks, dims the box to 50% opacity, and cancels its hover preview. */\n disabled?: boolean;\n /**\n * Whether the click stops bubbling to an ancestor. Defaults to `true`,\n * which is what a row that toggles on its own click needs. Set `false`\n * when the ancestor should also see the click -- e.g. a row that both\n * selects and opens a detail panel.\n */\n stopPropagation?: boolean;\n /** Forwarded as `data-testid`, for Playwright/test selectors. */\n testId?: string;\n /**\n * Native tooltip -- e.g. explaining why a disabled box is disabled. Forwarded\n * directly to the underlying `<button>`, same as a plain HTML `title` would\n * be on any other disabled control.\n */\n title?: string;\n /** Extra classes merged onto the box -- e.g. a cursor or margin override. */\n className?: string;\n}\n\nexport function CheckBox({\n checked,\n indeterminate,\n onChange,\n ariaLabel,\n disabled,\n stopPropagation = true,\n testId,\n title,\n className,\n}: CheckBoxProps) {\n const on = checked || !!indeterminate;\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={indeterminate ? \"mixed\" : checked}\n aria-label={ariaLabel}\n title={title}\n disabled={disabled}\n data-testid={testId}\n onClick={(e) => {\n // Stops the click from bubbling to a row wrapper that toggles on its\n // own click -- without this, a checkbox nested in such a row fires\n // its own onChange AND the row's, double-toggling back to a no-op.\n if (stopPropagation) e.stopPropagation();\n onChange();\n }}\n className={cn(\n boxClass(on, disabled),\n \"focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n !on && \"hover:border-brand-primaryAction\",\n // Cancels the unchecked hover-border preview when disabled -- without\n // this, a disabled box still visually previews the \"you can click\n // this\" affordance on hover even though the click does nothing.\n disabled && \"hover:border-border-interactive\",\n className\n )}\n >\n <Glyph checked={checked} indeterminate={indeterminate} />\n </button>\n );\n}\n\n/**\n * @pattern CheckBoxBox\n * @description Presentational checkbox -- draws the same box as `CheckBox`\n * and nothing else. Use it when an ancestor already carries the interaction\n * and the checkbox semantics (a clickable option row, a `<label>`), since a\n * `<button>` inside a `<button>` is invalid markup and a second focus stop on\n * the same control is worse for keyboard users, not better. The owning\n * element supplies `role=\"checkbox\"` and `aria-checked`; this is\n * `aria-hidden` so the state isn't announced twice.\n * @tokens bg-brand-primaryAction, border-border-interactive, bg-input\n * @dependencies lucide-react\n * @behavior Renders through the same `boxClass` as `CheckBox`, so geometry\n * and fill can't drift. Takes neither the focus ring nor the hover border,\n * because the row around it owns both. Without this, a row that is itself\n * the control has no correct option: nesting the interactive `CheckBox`\n * produces a button inside a button, and dropping to a `<div>` with a click\n * handler loses keyboard access entirely.\n * @a11y Presentational only: aria-hidden, no focus stop, no click handling. The\n * ancestor owns role=\"checkbox\", aria-checked, the accessible name and the\n * click. Use it exactly when that ancestor is itself the control; use\n * CheckBox when the box is the control.\n * @usage\n * ```tsx\n * <button type=\"button\" role=\"checkbox\" aria-checked={on} onClick={toggle}>\n * <CheckBoxBox checked={on} />\n * <span>Cable TV</span>\n * </button>\n * ```\n */\nexport interface CheckBoxBoxProps {\n /** Whether the box is checked. The owning element reports this to AT. */\n checked: boolean;\n /** Some-but-not-all state -- shows a dash instead of a check. */\n indeterminate?: boolean;\n /** Dims the box to 50% opacity, matching `CheckBox`'s disabled treatment. */\n disabled?: boolean;\n /** Extra classes merged onto the box. */\n className?: string;\n}\n\nexport function CheckBoxBox({ checked, indeterminate, disabled, className }: CheckBoxBoxProps) {\n return (\n <span aria-hidden=\"true\" className={cn(boxClass(checked || !!indeterminate, disabled), className)}>\n <Glyph checked={checked} indeterminate={indeterminate} />\n </span>\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { ChevronDown, ChevronLeft, ChevronRight } from \"lucide-react\";\n\nconst DEFAULT_SHORTCUTS = [\n \"Year to date\",\n \"Rolling 3 months\",\n \"Rolling 6 months\",\n \"Rolling 12 months\",\n \"Previous quarter\",\n \"Current quarter to date\",\n \"Previous month\",\n \"Current month\",\n \"Custom\",\n] as const;\n\n// Creative Intel's own preset list -- day-level shortcuts (Today/Yesterday/Last\n// N days) plus a longer history option, distinct from the quarter-oriented set\n// the other dashboards use. Content and order confirmed identical to\n// mr-clientapps-insights-studio's own hardcoded PRESETS list (its\n// DateRangeCalendar.tsx) -- this is that same list, made representable via a\n// prop instead of forked into a second hardcoded copy.\nconst CREATIVE_INTEL_SHORTCUTS = [\n \"Today\",\n \"Yesterday\",\n \"Last 7 days\",\n \"Last 14 days\",\n \"Last month\",\n \"Rolling 3 months\",\n \"Rolling 6 months\",\n \"Rolling 12 months\",\n \"Year to date\",\n \"Previous year\",\n \"All available history\",\n \"Custom\",\n] as const;\n\ntype Shortcut = (typeof DEFAULT_SHORTCUTS)[number] | (typeof CREATIVE_INTEL_SHORTCUTS)[number];\n\nconst WEEKDAYS = [\"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\", \"Su\"];\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n];\n\n// ── date helpers ─────────────────────────────────────────────────────────────\nconst startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate());\nconst addDays = (d: Date, n: number) => {\n const x = new Date(d);\n x.setDate(x.getDate() + n);\n return x;\n};\nconst addMonths = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth() + n, 1);\nconst sameDay = (a: Date, b: Date) =>\n a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\nconst fmt = (d: Date) => `${MONTHS[d.getMonth()].slice(0, 3)} ${d.getDate()}, ${d.getFullYear()}`;\n/** Full resolved range, e.g. \"December 16, 2025 - June 16, 2026\". */\nconst fmtFull = (d: Date) => `${MONTHS[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;\nconst fullRangeLabel = (s: Date, e: Date) => `${fmtFull(s)} - ${fmtFull(e)}`;\nconst presetLabel = (sc: Shortcut) => (sc === \"Custom\" ? \"Custom range\" : sc);\n\nfunction presetRange(key: Shortcut, today: Date): [Date, Date] | null {\n const t = startOfDay(today);\n const qMonth = Math.floor(t.getMonth() / 3) * 3;\n switch (key) {\n case \"Year to date\": return [new Date(t.getFullYear(), 0, 1), t];\n case \"Rolling 3 months\": return [addMonths(t, -3), t];\n case \"Rolling 6 months\": return [addMonths(t, -6), t];\n case \"Rolling 12 months\": return [addMonths(t, -12), t];\n case \"Previous quarter\": {\n const s = new Date(t.getFullYear(), qMonth - 3, 1);\n const e = new Date(t.getFullYear(), qMonth, 0);\n return [s, e];\n }\n case \"Current quarter to date\": return [new Date(t.getFullYear(), qMonth, 1), t];\n case \"Previous month\": {\n const s = new Date(t.getFullYear(), t.getMonth() - 1, 1);\n const e = new Date(t.getFullYear(), t.getMonth(), 0);\n return [s, e];\n }\n case \"Current month\": return [new Date(t.getFullYear(), t.getMonth(), 1), t];\n case \"Today\": return [t, t];\n case \"Yesterday\": { const y = addDays(t, -1); return [y, y]; }\n case \"Last 7 days\": return [addDays(t, -6), t];\n case \"Last 14 days\": return [addDays(t, -13), t];\n case \"Last month\": {\n const s = new Date(t.getFullYear(), t.getMonth() - 1, 1);\n const e = new Date(t.getFullYear(), t.getMonth(), 0);\n return [s, e];\n }\n case \"Previous year\": return [new Date(t.getFullYear() - 1, 0, 1), new Date(t.getFullYear() - 1, 11, 31)];\n case \"All available history\": return [new Date(2000, 0, 1), t];\n default: return null; // Custom\n }\n}\n\n/** 42-cell (6-week) Monday-first grid for a given month. */\nfunction monthGrid(year: number, month: number): Date[] {\n const first = new Date(year, month, 1);\n const dow = (first.getDay() + 6) % 7; // Mon = 0\n const gridStart = addDays(first, -dow);\n return Array.from({ length: 42 }, (_, i) => addDays(gridStart, i));\n}\n\nfunction matchShortcut(shortcuts: readonly Shortcut[], label?: string): Shortcut {\n if (!label) return \"Rolling 12 months\";\n const hit = shortcuts.find((s) => s.toLowerCase() === label.toLowerCase());\n return hit || \"Custom\";\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens -- used for each preset\n * option's data-testid. NOTE: this does not match mr-clientapps' own\n * CreativeDatePreset enum keys 1:1 (e.g. \"Last 7 days\" -> \"last-7-days\"\n * here, vs. its \"last7\") -- a consumer with existing Playwright locators\n * keyed off those enum values needs to update them to this slug format,\n * or the caller needs a custom id mapping; not attempted here since no\n * generic per-option id override existed to build on. */\nfunction slug(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/(^-|-$)/g, \"\");\n}\n\n/**\n * @pattern DateRangeFilter\n * @description Date-range control -- the two-line chip (caption + value) with\n * a chevron that opens a two-pane picker: preset shortcuts on the left, a\n * dual-month calendar with range highlighting on the right, Start/End fields,\n * and Cancel/Apply. Shared by Creative Intel and the Account Review.\n * @tokens rounded-control, rounded-card, border-border-default, border-border-strong,\n * bg-surface, bg-input, bg-subtle, bg-ai-tint, bg-brand-primaryAction,\n * shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary,\n * hover:bg-subtle, hover:text-text-primary, focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior Escape and outside-click both close the popup. Opening always\n * resets the draft (shortcut/start/end/visible month) to the last committed\n * values, so a previous unsaved edit never lingers into the next open. Only\n * the Apply button commits -- Cancel, Escape, and outside-click all discard\n * the draft silently.\n * @a11y Trigger is a <button> with aria-expanded and an aria-label from the\n * caption; the panel is role=\"dialog\" and Escape closes it. Focus is not\n * moved into the panel, so it is reached by tabbing.\n * @usage\n * ```tsx\n * <DateRangeFilter caption=\"Date Range\" defaultValue=\"Rolling 6 months\" onChange={setRange} />\n * <DateRangeFilter presetSet=\"creativeIntel\" defaultValue=\"Last 7 days\" onChange={setRange} />\n * <DateRangeFilter presetSet=\"creativeIntel\" value={preset} range={[start, end]} onChange={setPreset} onRangeChange={(s, e) => setRange({ start: s, end: e })} />\n * ```\n */\nexport interface DateRangeFilterProps {\n /** Static label shown above the value when `showDates` is false. */\n caption?: string;\n /** Initial preset (matched case-insensitively against the active preset set) or, if unmatched, treated as a custom label. Ignored once `value`/`range` are given -- see those. */\n defaultValue?: string;\n /**\n * Controlled mode: the parent owns the committed preset/range instead of\n * this component tracking it internally. Give both `value` and `range`\n * together to enable it -- omit both (the default) for the original\n * uncontrolled behavior, where `defaultValue` seeds the initial state and\n * `onChange`/`onRangeChange` are fire-and-forget notifications. In\n * controlled mode the chip's displayed value/dates always reflect these\n * props directly, so the parent must call `onChange`/`onRangeChange` and\n * feed the result back for the chip to update after Apply -- the same\n * contract as a controlled `<input value onChange>`.\n */\n value?: string;\n /** Controlled mode's resolved range -- see `value`. */\n range?: [Date, Date];\n /** Which edge of the trigger the popup aligns to. */\n align?: \"left\" | \"right\";\n /** Fired on Apply with the chip's new display value. */\n onChange?: (value: string) => void;\n /** Fired on Apply (and once on mount, uncontrolled only) with the resolved start/end dates -- e.g. to drive dependent table columns. */\n onRangeChange?: (start: Date, end: Date) => void;\n /** Show the resolved start-end dates in the chip instead of the preset name. */\n showDates?: boolean;\n /** Use an abbreviated date format (e.g. \"Dec 1, 2025 - Jun 24, 2026\") for the dates line. */\n shortDates?: boolean;\n /** Optional leading icon rendered before the caption/value stack. */\n icon?: React.ReactNode;\n /** 'creativeIntel' swaps in the day-level shortcut list (Today/Yesterday/Last N days/All available history) used by that dashboard. */\n presetSet?: \"default\" | \"creativeIntel\";\n /** Prefix for data-testid attributes on the trigger, popover, each preset option, and Cancel/Apply. Omit for no test-id wiring. */\n testIdPrefix?: string;\n}\n\nexport function DateRangeFilter({\n caption = \"Date Range\",\n defaultValue,\n value: controlledValue,\n range: controlledRange,\n align = \"left\",\n onChange,\n onRangeChange,\n showDates = false,\n shortDates = false,\n icon,\n presetSet = \"default\",\n testIdPrefix,\n}: DateRangeFilterProps) {\n const controlled = controlledValue !== undefined && controlledRange !== undefined;\n const SHORTCUTS = presetSet === \"creativeIntel\" ? CREATIVE_INTEL_SHORTCUTS : DEFAULT_SHORTCUTS;\n const today = useMemo(() => new Date(), []);\n const initShortcut = matchShortcut(SHORTCUTS, controlled ? controlledValue : defaultValue);\n const initRange = (\n controlled ? controlledRange! : (presetRange(initShortcut === \"Custom\" ? \"Rolling 12 months\" : initShortcut, today) as [Date, Date])\n );\n const dateLine = (s: Date, e: Date) => (shortDates ? `${fmt(s)} – ${fmt(e)}` : fullRangeLabel(s, e));\n\n const [open, setOpen] = useState(false);\n // Uncontrolled-only: the chip's own tracked value/dates line, seeded from\n // defaultValue. In controlled mode the chip reads controlledValue/\n // controlledRange directly every render instead (see `displayValue`/\n // `displayDatesLine` below) -- these two pieces of state are simply unused\n // then, since the parent's props are the single source of truth.\n const [uncontrolledValue, setUncontrolledValue] = useState(\n showDates ? presetLabel(initShortcut) : defaultValue || \"Last 7 days\"\n );\n const [uncontrolledDatesLine, setUncontrolledDatesLine] = useState(dateLine(initRange[0], initRange[1]));\n // Uncontrolled-only committed state (what the chip reflects between opens).\n // In controlled mode, controlledValue/controlledRange play this role\n // instead -- always current, since they come from the parent every render,\n // never going stale the way a ref seeded once at mount would.\n const committed = useRef({ shortcut: initShortcut, start: initRange[0], end: initRange[1] });\n const displayValue = controlled ? (showDates ? presetLabel(initShortcut) : controlledValue!) : uncontrolledValue;\n const displayDatesLine = controlled ? dateLine(initRange[0], initRange[1]) : uncontrolledDatesLine;\n // draft state (inside the open popup)\n const [shortcut, setShortcut] = useState<Shortcut>(initShortcut);\n const [start, setStart] = useState<Date | null>(initRange[0]);\n const [end, setEnd] = useState<Date | null>(initRange[1]);\n const [leftMonth, setLeftMonth] = useState<Date>(new Date(initRange[0].getFullYear(), initRange[0].getMonth(), 1));\n const ref = useRef<HTMLDivElement>(null);\n\n // Emit the initial range once on mount so dependent views start in sync --\n // uncontrolled only. A controlled caller already owns and passes in the\n // starting range itself, so there's nothing to announce.\n useEffect(() => {\n if (controlled) return;\n onRangeChange?.(committed.current.start, committed.current.end);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!open) return;\n // Reset the draft to the committed value each time it opens -- from\n // props directly in controlled mode (always current), from the internal\n // ref otherwise.\n const committedShortcut = controlled ? initShortcut : committed.current.shortcut;\n const committedStart = controlled ? initRange[0] : committed.current.start;\n const committedEnd = controlled ? initRange[1] : committed.current.end;\n setShortcut(committedShortcut);\n setStart(committedStart);\n setEnd(committedEnd);\n setLeftMonth(new Date(committedStart.getFullYear(), committedStart.getMonth(), 1));\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n const choosePreset = (key: Shortcut) => {\n setShortcut(key);\n if (key === \"Custom\") return;\n const r = presetRange(key, today);\n if (r) { setStart(r[0]); setEnd(r[1]); setLeftMonth(new Date(r[0].getFullYear(), r[0].getMonth(), 1)); }\n };\n\n const pickDay = (d: Date) => {\n setShortcut(\"Custom\");\n if (!start || (start && end)) { setStart(d); setEnd(null); }\n else if (d < start) { setEnd(start); setStart(d); }\n else setEnd(d);\n };\n\n const apply = () => {\n const s = start || initRange[0];\n const e = end || s;\n const v = showDates ? presetLabel(shortcut) : shortcut === \"Custom\" ? `${fmt(s)} — ${fmt(e)}` : shortcut;\n // Uncontrolled only: track the new committed value/dates ourselves. In\n // controlled mode this is the parent's job -- it owns `value`/`range`\n // and is expected to feed the updated ones back in via its own state,\n // same contract as a controlled <input value onChange>.\n if (!controlled) {\n committed.current = { shortcut, start: s, end: e };\n setUncontrolledValue(v);\n setUncontrolledDatesLine(dateLine(s, e));\n }\n onChange?.(v);\n onRangeChange?.(s, e);\n setOpen(false);\n };\n\n // Inlined here rather than depending on the (not-yet-migrated) ChipTrigger\n // pattern's `chipTriggerClass` -- this package can't import an app-local\n // helper from insights-studio-prototype, and the trigger visual is simple\n // enough not to need a shared abstraction of its own yet.\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-trigger`}\n onClick={() => setOpen((v) => !v)}\n aria-expanded={open}\n className=\"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n {icon && <span className=\"shrink-0 text-text-tertiary\">{icon}</span>}\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className={showDates ? \"text-[11px] text-text-tertiary\" : \"text-[10px] uppercase tracking-wide text-text-tertiary\"}>\n {showDates ? displayDatesLine : caption}\n </span>\n <span className=\"text-[12px] font-medium text-text-primary\">{displayValue}</span>\n </span>\n <ChevronDown size={14} aria-hidden=\"true\" className={`shrink-0 text-text-secondary transition-transform ${open ? \"rotate-180\" : \"\"}`} />\n </button>\n\n {open && (\n <div\n data-testid={testIdPrefix && `${testIdPrefix}-popover`}\n className={`absolute top-[calc(100%+8px)] z-30 flex overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay ${align === \"right\" ? \"right-0\" : \"left-0\"}`}\n role=\"dialog\"\n aria-label=\"Select date range\"\n >\n {/* Shortcuts rail */}\n <div className=\"flex w-44 shrink-0 flex-col gap-0.5 border-r border-border-default p-2\">\n {SHORTCUTS.map((s) => (\n <button\n key={s}\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-option-${slug(s)}`}\n onClick={() => choosePreset(s)}\n className={`rounded-control px-3 py-2 text-left text-[13px] font-medium transition-colors ${\n shortcut === s ? \"bg-subtle text-text-primary\" : \"text-text-secondary hover:bg-subtle hover:text-text-primary\"\n }`}\n >\n {s}\n </button>\n ))}\n </div>\n\n {/* Calendar pane */}\n <div className=\"flex flex-col p-4\">\n {/* Start / End fields */}\n <div className=\"flex items-end gap-3\">\n <Field label=\"Start Date\" value={start ? fmt(start) : \"—\"} />\n <span className=\"pb-2.5 text-text-tertiary\">{\"—\"}</span>\n <Field label=\"End Date\" value={end ? fmt(end) : start ? fmt(start) : \"—\"} />\n </div>\n\n <div className=\"my-4 border-t border-border-default\" />\n\n {/* Two months */}\n <div className=\"flex gap-8\">\n {[0, 1].map((offset) => {\n const m = addMonths(leftMonth, offset);\n const grid = monthGrid(m.getFullYear(), m.getMonth());\n return (\n <div key={offset} className=\"w-[252px]\">\n <div className=\"mb-2 flex items-center justify-between\">\n {offset === 0 ? (\n <NavBtn onClick={() => setLeftMonth(addMonths(leftMonth, -1))} aria-label=\"Previous month\"><ChevronLeft size={16} /></NavBtn>\n ) : <span className=\"h-7 w-7\" />}\n <span className=\"text-[15px] font-semibold text-text-primary\">{MONTHS[m.getMonth()]} {m.getFullYear()}</span>\n {offset === 1 ? (\n <NavBtn onClick={() => setLeftMonth(addMonths(leftMonth, 1))} aria-label=\"Next month\"><ChevronRight size={16} /></NavBtn>\n ) : <span className=\"h-7 w-7\" />}\n </div>\n <div className=\"grid grid-cols-7\">\n {WEEKDAYS.map((w) => (\n <div key={w} className=\"flex h-8 items-center justify-center text-[12px] font-semibold text-text-secondary\">{w}</div>\n ))}\n {grid.map((d, i) => {\n const inMonth = d.getMonth() === m.getMonth();\n const hasRange = !!(start && end);\n const isStart = !!start && sameDay(d, start);\n const isEnd = end ? sameDay(d, end) : isStart && !end;\n const inRange = hasRange && d >= startOfDay(start!) && d <= startOfDay(end!);\n const single = isStart && isEnd;\n const endpoint = isStart || (!!end && isEnd);\n // band geometry\n let band = \"\";\n if (inRange && !single) {\n if (isStart) band = \"left-1/2 right-0\";\n else if (end && isEnd) band = \"left-0 right-1/2\";\n else band = \"left-0 right-0\";\n }\n return (\n <button key={i} type=\"button\" onClick={() => pickDay(d)} className=\"relative flex h-9 items-center justify-center\">\n {band && <span className={`absolute inset-y-[3px] bg-ai-tint ${band}`} aria-hidden=\"true\" />}\n <span\n className={`relative z-10 flex h-8 w-8 items-center justify-center rounded-full text-[13px] tabular-nums ${\n endpoint ? \"bg-brand-primaryAction font-semibold text-white\" : inMonth ? \"text-text-primary hover:bg-subtle\" : \"text-text-tertiary\"\n }`}\n >\n {d.getDate()}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Actions */}\n <div className=\"mt-4 flex justify-end gap-2\">\n <button type=\"button\" data-testid={testIdPrefix && `${testIdPrefix}-cancel`} onClick={() => setOpen(false)} className=\"rounded-control border border-border-default bg-surface px-5 py-2 text-[13px] font-semibold text-text-primary transition-colors hover:bg-subtle\">Cancel</button>\n <button type=\"button\" data-testid={testIdPrefix && `${testIdPrefix}-apply`} onClick={apply} className=\"rounded-control bg-brand-primaryAction px-5 py-2 text-[13px] font-semibold text-white transition-[filter] hover:brightness-110\">Apply</button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction Field({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-[12px] font-medium text-text-secondary\">{label}</span>\n <div className=\"flex h-10 min-w-[140px] items-center rounded-control border border-border-default bg-input px-3 text-[14px] font-medium text-text-primary\">{value}</div>\n </div>\n );\n}\n\nfunction NavBtn({ children, onClick, ...rest }: { children: React.ReactNode; onClick: () => void; \"aria-label\": string }) {\n return (\n <button type=\"button\" onClick={onClick} className=\"flex h-7 w-7 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary\" {...rest}>\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { AlertCircle, Check, ChevronDown, Search } from \"lucide-react\";\n\n/**\n * @pattern SearchBar\n * @description Filter-bar keyword search. 'default' is a plain keyword\n * input; 'filterable' adds an attached match-type dropdown sharing one\n * bordered control, mirroring the legacy Creative Intel search + match-type\n * modal (Any Word/Exact Match/Contextual/Ad Code), including the Or/And\n * sub-choice nested under Any Word.\n * @tokens rounded-control, border-border-strong, bg-input, text-text-primary,\n * text-text-tertiary, hover:bg-subtle, bg-brand-primaryAction, bg-subtle,\n * bg-surface, border-brand-primaryAction, border-border-default,\n * border-border-interactive, focus-visible:outline-border-focus,\n * hover:text-text-primary, placeholder:text-text-tertiary, rounded-card,\n * rounded-full, shadow-overlay, text-brand-primaryAction, text-text-secondary\n * @variant default - Default. Plain keyword input, no match-type control.\n * @variant filterable - Adds an attached match-type dropdown sharing one\n * bordered control, mirroring the legacy Creative Intel search + match-type\n * modal (Any Word/Exact Match/Contextual/Ad Code), including the Or/And\n * sub-choice nested under Any Word.\n * @dependencies lucide-react\n * @behavior The match-type dropdown ('filterable' variant) closes on Escape\n * and outside click. Each mode row is a real `radio` role, with a nested\n * Or/And sub-choice under Any Word and its own click-to-toggle info tooltip.\n * The text input carries an `aria-label` derived from `placeholder` — the\n * wrapping `<label>` has no visible text content (just an icon and the\n * input), so it grants the input no accessible name on its own.\n * @a11y The <input> takes its accessible name from `ariaLabel`. The match-mode\n * popover is a radio group (role=\"radio\" + aria-checked) and its trigger\n * reports aria-expanded. Escape closes the popover only, leaving focus in\n * the field -- a consumer nesting this inside another dismissible layer\n * must sequence the two dismissals itself.\n * @usage\n * ```tsx\n * <SearchBar value={query} onChange={setQuery} />\n * <SearchBar variant=\"filterable\" value={query} onChange={setQuery} matchValue={matchValue} onMatchChange={setMatchValue} />\n * ```\n */\nexport type SearchBarVariant = \"default\" | \"filterable\";\n\nexport type SearchMatchMode = \"anyWord\" | \"exactMatch\" | \"contextual\" | \"adCode\";\n\nexport interface SearchMatchValue {\n mode: SearchMatchMode;\n /** Only meaningful when mode === 'anyWord'. */\n wordJoin: \"Or\" | \"And\";\n}\n\nexport const DEFAULT_SEARCH_MATCH: SearchMatchValue = { mode: \"anyWord\", wordJoin: \"Or\" };\n\nconst MODE_LABEL: Record<SearchMatchMode, string> = {\n anyWord: \"Any Word\",\n exactMatch: \"Exact Match\",\n contextual: \"Contextual\",\n adCode: \"Ad Code\",\n};\n\n/** Joins conditional class fragments — this package has no clsx/tailwind-merge dependency, and none of the classes below actually conflict, so a plain filter+join is enough. */\nfunction cx(...classes: Array<string | false | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\nexport interface SearchBarProps {\n /** Input placeholder text. Also used as the input's `aria-label`. */\n placeholder?: string;\n value?: string;\n onChange?: (v: string) => void;\n /** 'default' is a plain keyword input; 'filterable' adds the match-type dropdown. */\n variant?: SearchBarVariant;\n /** The 'filterable' variant's dropdown state. */\n matchValue?: SearchMatchValue;\n onMatchChange?: (v: SearchMatchValue) => void;\n className?: string;\n /**\n * Optional prefix for `data-testid` attributes on the input, the\n * match-type trigger/popover, each mode row, and the Or/And radio pair\n * (e.g. `${testIdPrefix}-search`, `${testIdPrefix}-mode-trigger`,\n * `${testIdPrefix}-mode-anyWord`, `${testIdPrefix}-word-join-or`). Omit\n * entirely for no test-id wiring at all -- added specifically so an\n * existing Playwright suite keyed off these ids (mr-clientapps'\n * `KeywordSearchBar`) doesn't lose its locators when swapped over to\n * this shared component.\n */\n testIdPrefix?: string;\n}\n\nexport function SearchBar({\n placeholder = \"Search…\",\n value,\n onChange,\n variant = \"default\",\n matchValue,\n onMatchChange,\n className,\n testIdPrefix,\n}: SearchBarProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n };\n }, [open]);\n\n const showMatch = variant === \"filterable\" && matchValue;\n\n return (\n <div\n className={cx(\n \"flex h-11 min-w-[200px] flex-1 items-stretch rounded-control border border-border-strong bg-input\",\n className\n )}\n >\n <label className=\"flex min-w-0 flex-1 items-center gap-2 px-2.5\">\n <Search size={15} aria-hidden=\"true\" className=\"shrink-0 text-text-tertiary\" />\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange?.(e.target.value)}\n placeholder={placeholder}\n aria-label={placeholder}\n data-testid={testIdPrefix && `${testIdPrefix}-search`}\n className=\"min-w-0 flex-1 bg-transparent text-[13px] text-text-primary outline-hidden placeholder:text-text-tertiary\"\n />\n </label>\n {showMatch && (\n // border-border-default, not the bare `border-border` both source\n // implementations used -- confirmed by actually compiling against\n // @mediaradar/design-tokens' real published theme.css (not assumed):\n // there is no bare `--color-border` in that file, only the\n // -default/-interactive/-focus/-focusSoft/-strong suffixed variants,\n // so `border-border` silently generates no utility at all there. It\n // only \"worked\" in each source app because each one separately\n // defines its own local `border-border` alias outside the shared\n // token package (insights-studio-prototype's own src/index.css;\n // mr-clientapps' own tailwind.config.ts `colors.border.DEFAULT`) --\n // an alias this shared component can't rely on existing.\n <div className=\"relative shrink-0 border-l border-border-default\" ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-mode-trigger`}\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-haspopup=\"dialog\"\n className=\"flex h-full items-center gap-1 px-2.5 text-[13px] font-medium text-text-primary transition-colors hover:bg-subtle\"\n >\n {matchValue.mode === \"anyWord\" ? `${MODE_LABEL.anyWord} (${matchValue.wordJoin})` : MODE_LABEL[matchValue.mode]}\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n {open && (\n <div\n role=\"dialog\"\n aria-label=\"Search match type\"\n data-testid={testIdPrefix && `${testIdPrefix}-mode-popover`}\n // shadow-overlay, not mr-clientapps' `shadow-2` -- same stale-\n // local-name issue InfoTip's reconciliation already found:\n // `shadow-2` doesn't exist anywhere in @mediaradar/design-tokens\n // (only shadow-raised/shadow-overlay do), it's a value hand-\n // copied into mr-clientapps' own tailwind.config.ts `boxShadow`\n // extension rather than referencing the shared token.\n className=\"absolute right-0 top-[calc(100%+8px)] z-50 w-[400px] rounded-card border border-border-default bg-surface p-3 shadow-overlay\"\n >\n <div role=\"radiogroup\" aria-label=\"Search match type\" className=\"flex flex-col\">\n <ModeRow\n title=\"Any Word Text Search\"\n selected={matchValue.mode === \"anyWord\"}\n onSelect={() => onMatchChange?.({ mode: \"anyWord\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-anyWord`}\n description={\n <>\n Find creatives that contain your keyword(s) using an &ldquo;Or&rdquo; (match any) or &ldquo;And&rdquo; (match all)\n conditional in any order.\n </>\n }\n infoText=\"The Or/And choice applies only when Any Word is the active search mode.\"\n extra={\n <span className=\"flex items-center gap-3\">\n <RadioOption\n label=\"Or\"\n checked={matchValue.wordJoin === \"Or\"}\n onSelect={() => onMatchChange?.({ mode: \"anyWord\", wordJoin: \"Or\" })}\n testId={testIdPrefix && `${testIdPrefix}-word-join-or`}\n />\n <RadioOption\n label=\"And\"\n checked={matchValue.wordJoin === \"And\"}\n onSelect={() => onMatchChange?.({ mode: \"anyWord\", wordJoin: \"And\" })}\n testId={testIdPrefix && `${testIdPrefix}-word-join-and`}\n />\n </span>\n }\n />\n <Divider />\n <ModeRow\n title=\"Exact Match Text Search\"\n selected={matchValue.mode === \"exactMatch\"}\n onSelect={() => onMatchChange?.({ mode: \"exactMatch\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-exactMatch`}\n description=\"Find creatives that mention your exact keyword phrase.\"\n infoText=\"Keywords are matched as a single contiguous phrase, in the order you typed them.\"\n />\n <Divider />\n <ModeRow\n title=\"Contextual Search\"\n badge=\"Beta\"\n selected={matchValue.mode === \"contextual\"}\n onSelect={() => onMatchChange?.({ mode: \"contextual\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-contextual`}\n description=\"Find creatives that may contain OR have similar meaning as your keyword(s).\"\n infoText=\"Uses semantic matching, so results can include related terms even when the exact keyword isn't present.\"\n />\n <Divider />\n <ModeRow\n title=\"Ad Code Search\"\n selected={matchValue.mode === \"adCode\"}\n onSelect={() => onMatchChange?.({ mode: \"adCode\", wordJoin: matchValue.wordJoin })}\n testId={testIdPrefix && `${testIdPrefix}-mode-adCode`}\n description=\"Find creatives based on a list of one or more ad codes that you provide.\"\n infoText=\"Separate multiple ad codes with a comma or a new line.\"\n />\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction Divider() {\n return <div className=\"my-2.5 border-t border-border-default\" aria-hidden=\"true\" />;\n}\n\n/** One selectable search-mode block — title (+ optional badge/extra controls), description, and a trailing checkmark when active. */\nfunction ModeRow({\n title,\n badge,\n extra,\n description,\n infoText,\n selected,\n onSelect,\n testId,\n}: {\n title: string;\n badge?: string;\n extra?: React.ReactNode;\n description: React.ReactNode;\n infoText: string;\n selected: boolean;\n onSelect: () => void;\n testId?: string;\n}) {\n return (\n <div\n role=\"radio\"\n tabIndex={0}\n aria-checked={selected}\n data-testid={testId}\n onClick={onSelect}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect();\n }\n }}\n // outline-solid, not a bare `outline` (mr-clientapps' spelling) --\n // same fallback InfoTip's reconciliation already flagged: bare\n // `outline` only renders solid because Tailwind v4's `--tw-outline-\n // style` custom property happens to declare `solid` as its @property\n // initial-value, not because the utility sets it explicitly. Confirmed\n // by compiling both against the real theme.css.\n className=\"flex cursor-pointer flex-col items-stretch gap-1 rounded-control p-1.5 text-left transition-colors hover:bg-subtle focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"flex items-center gap-1\">\n <span className=\"text-[14px] font-semibold text-text-primary\">{title}</span>\n <RowInfoTip text={infoText} />\n </span>\n {badge && (\n <span className=\"rounded-full bg-subtle px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-text-secondary\">\n {badge}\n </span>\n )}\n {extra}\n </div>\n {selected && <Check size={16} strokeWidth={2.5} aria-hidden=\"true\" className=\"shrink-0 text-brand-primaryAction\" />}\n </div>\n <span className=\"block text-[12.5px] leading-snug text-text-secondary\">{description}</span>\n </div>\n );\n}\n\n/** Single radio-style choice used inline in the Any Word row (Or / And). */\nfunction RadioOption({\n label,\n checked,\n onSelect,\n testId,\n}: {\n label: string;\n checked: boolean;\n onSelect: () => void;\n testId?: string;\n}) {\n return (\n <button\n type=\"button\"\n data-testid={testId}\n onClick={(e) => {\n e.stopPropagation();\n onSelect();\n }}\n role=\"radio\"\n aria-checked={checked}\n className=\"flex items-center gap-1.5 text-[13px] font-medium text-text-primary\"\n >\n <span\n className={cx(\n \"flex h-4 w-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors\",\n checked ? \"border-brand-primaryAction\" : \"border-border-interactive\"\n )}\n >\n {/*\n text-brand-primaryAction / bg-brand-primaryAction / border-brand-\n primaryAction throughout this file, not insights-studio-prototype's\n `text-(--color-brand-primary-action)` (Tailwind v4 arbitrary-\n property syntax referencing a literal, dash-cased CSS variable).\n Confirmed by compiling against the real, published theme.css: that\n exact variable name is never defined there -- only the camelCase\n `--color-brand-primaryAction` is (theme.css line 63). The dash-case\n form only resolves in prototype today because prototype's own\n src/index.css / src/styles/tokens.css separately hand-define that\n alias; mr-clientapps' `text-brand-primaryAction` (its own\n tailwind.config.ts extends `colors.brand.primaryAction` the same\n way) happens to already match the shared package's real name.\n */}\n {checked && <span className=\"h-2 w-2 rounded-full bg-brand-primaryAction\" />}\n </span>\n {label}\n </button>\n );\n}\n\n/** Small click-to-toggle tooltip on an alert-circle glyph, trailing a mode's description. */\nfunction RowInfoTip({ text }: { text: string }) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLSpanElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n return (\n <span className=\"relative inline-flex shrink-0 items-center\" ref={ref}>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setOpen((o) => !o);\n }}\n aria-label=\"More information\"\n aria-expanded={open}\n className=\"inline-flex text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <AlertCircle size={13} aria-hidden=\"true\" />\n </button>\n {open && (\n <span\n role=\"tooltip\"\n className=\"absolute left-0 top-[calc(100%+6px)] z-40 w-[220px] rounded-control border border-border-default bg-surface px-2.5 py-1.5 text-[11.5px] font-normal leading-snug text-text-secondary shadow-overlay\"\n >\n {text}\n </span>\n )}\n </span>\n );\n}\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\n\n/**\n * @pattern SectionRail\n * @description Generic titled section wrapper for a row of cards — a\n * horizontal scroll rail on mobile/tablet (snap, bleeds to edges), a\n * left-aligned 4-column grid on desktop. Card width is handled here, not on\n * the card itself, so cards stay layout-agnostic; it works with any\n * `children`. Real call sites vary: a fixed 4-item row that fills the\n * desktop grid exactly, or a variable-length list with no \"view all\" link\n * at all — both need to keep working without the row assuming a count.\n * @tokens text-text-primary, text-text-secondary, text-text-link,\n * rounded-control, rounded-sm, border-border-default, focus-visible:outline-solid,\n * focus-visible:outline-border-focus, hover:bg-subtle, hover:text-text-primary,\n * tracking-tight, font-serif\n * @dependencies lucide-react\n * @behavior Card width lives on the row, not the card: a fixed 268px per\n * card in rail mode, capped at 320px per column in the lg+ grid, so cards\n * stay layout-agnostic. The \"view all\" link only renders when both\n * `viewAllLabel` and `viewAllHref` are given — either alone hides it, rather\n * than falling back to a dead `href=\"#\"`. Prev/next arrows are hidden below\n * `sm` (swipe is the native affordance there) and at `lg`+ (the grid shows\n * every card, nothing left to scroll to). `viewAllHref` renders as a plain\n * anchor rather than a framework router Link — this package has no router\n * peer dependency, and the two consuming apps disagree on one (react-router-dom\n * vs next/link); a plain anchor is the one thing that works unmodified in both.\n * @a11y Rail items are buttons and take their accessible name from `ariaLabel`,\n * since several render icon-only. Without it they announce as unnamed\n * buttons.\n * @usage\n * ```tsx\n * <SectionRail title=\"Sports\" subtitle=\"Your tracked leagues\" viewAllLabel=\"View all\" viewAllHref=\"/sports\">\n * {items.map((i) => <Card key={i.id}>{i.name}</Card>)}\n * </SectionRail>\n * ```\n */\nexport interface SectionRailProps {\n /** Section heading. */\n title: string;\n /** Use the serif display treatment instead of the default sans heading. */\n titleSerif?: boolean;\n /** Supporting line under the title. */\n subtitle: string;\n /** Label for the \"view all\" link. Has no effect unless `viewAllHref` is also given. */\n viewAllLabel?: string;\n /** Route the \"view all\" link points to. Has no effect unless `viewAllLabel` is also given. */\n viewAllHref?: string;\n /** The row's cards. Any content works — width is handled by the row, not the card. */\n children: React.ReactNode;\n}\n\nexport function SectionRail({\n title,\n titleSerif,\n subtitle,\n viewAllLabel,\n viewAllHref,\n children,\n}: SectionRailProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const scroll = (direction: -1 | 1) => {\n scrollRef.current?.scrollBy({ left: direction * 320, behavior: \"smooth\" });\n };\n\n return (\n <section className=\"flex flex-col gap-4\">\n <header className=\"flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between\">\n {/* Title block */}\n <div>\n <h2\n className={\n titleSerif\n ? \"font-serif text-2xl font-normal tracking-tight text-text-primary sm:text-[28px]\"\n : \"text-xl font-medium tracking-tight text-text-primary sm:text-2xl\"\n }\n >\n {title}\n </h2>\n <p className=\"mt-1 text-sm text-text-secondary\">{subtitle}</p>\n </div>\n\n {/* Controls — link + scroll arrows.\n Arrows hidden on mobile (swipe is natural) AND on lg+ (no scroll, all cards visible). */}\n <div className=\"flex items-center gap-2\">\n {viewAllLabel && viewAllHref && (\n <a\n href={viewAllHref}\n className=\"text-sm font-medium text-text-link transition-colors hover:underline focus-visible:rounded-sm focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n {viewAllLabel} →\n </a>\n )}\n <button\n type=\"button\"\n onClick={() => scroll(-1)}\n aria-label=\"Previous\"\n className=\"hidden h-10 w-10 items-center justify-center rounded-control border border-border-default text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary sm:flex lg:hidden\"\n >\n <ChevronLeft size={16} />\n </button>\n <button\n type=\"button\"\n onClick={() => scroll(1)}\n aria-label=\"Next\"\n className=\"hidden h-10 w-10 items-center justify-center rounded-control border border-border-default text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary sm:flex lg:hidden\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n </header>\n\n {/* Card row.\n - Mobile / tablet: horizontal scroll rail with fixed 268px cards (snap, bleed to edges).\n - Desktop (lg+): 4-column grid, cards stretch to fill.\n The width handling lives here (on the row), not on the Card, so cards stay layout-agnostic. */}\n <div\n ref={scrollRef}\n className=\"flex gap-4 overflow-x-auto scroll-smooth pb-2 snap-x snap-mandatory scrollbar-none [&::-webkit-scrollbar]:hidden -mx-4 px-4 sm:mx-0 sm:px-0 *:w-[268px] *:shrink-0 *:snap-start lg:grid lg:grid-cols-[repeat(4,minmax(0,320px))] lg:gap-5 lg:overflow-visible lg:justify-start lg:*:w-auto lg:*:shrink lg:*:snap-none\"\n >\n {children}\n </div>\n </section>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Check, ChevronDown } from \"lucide-react\";\nimport { InfoTip } from \"./InfoTip\";\n\nconst FINAL_ONLY_TEXT =\n \"Trims time periods to data that has finalized across the selected media formats. Some formats (e.g. Network TV and Cinema) finalize later, so the most recent periods may still change. Turn on for stable, report-ready numbers.\";\n\n/** Joins conditional class fragments -- this package has no clsx/tailwind-merge dependency. */\nfunction cx(...classes: Array<string | false | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * @pattern DataScopeFilter\n * @description \"Data\" scope chip -- toggles the filter bar between All data\n * and Final-only data (data that's finalized across the selected media\n * formats, for stable report-ready numbers). One boolean, one control,\n * shared across every dashboard that has this data-finality concept\n * (Publisher Intel, Opportunities, Sports).\n * @tokens rounded-control, border-border-strong, bg-input, hover:bg-subtle,\n * hover:text-text-primary, focus-visible:outline-border-focus, rounded-card,\n * border-border-default, bg-surface, shadow-overlay, text-text-primary,\n * text-text-secondary, text-text-tertiary, text-brand-primaryAction\n * @dependencies lucide-react\n * @behavior Escape and outside-click both close the popover. The \"Final\n * only\" option's info tooltip is a real InfoTip in hover mode, rendered as a\n * sibling of the option button rather than nested inside it -- InfoTip\n * renders its own `<button>`, and a button nested inside another button is\n * invalid HTML that breaks click targeting (confirmed against how\n * mr-clientapps-insights-studio's own equivalent, `ChipOption`, already\n * avoids exactly this by rendering its InfoTip as a sibling, not a child).\n * @a11y Trigger is a <button> with aria-expanded and aria-haspopup; the menu is\n * role=\"listbox\" with role=\"option\" rows carrying aria-selected. Escape\n * closes it. Use the listbox semantics as given -- adding a second role to\n * the wrapper breaks the option/listbox relationship.\n * @usage\n * ```tsx\n * <DataScopeFilter value={finalOnly} onChange={setFinalOnly} />\n * ```\n */\nexport interface DataScopeFilterProps {\n value: boolean;\n onChange: (v: boolean) => void;\n /** Which edge of the trigger the popover aligns to. Both known consumers\n * anchor this at the right edge of a filter bar, hence the default. */\n align?: \"left\" | \"right\";\n}\n\nexport function DataScopeFilter({ value, onChange, align = \"right\" }: DataScopeFilterProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n const display = value ? \"Final only\" : \"All\";\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n window.addEventListener(\"mousedown\", onDown);\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"mousedown\", onDown);\n window.removeEventListener(\"keydown\", onKey);\n };\n }, [open]);\n\n const choose = (v: boolean) => {\n onChange(v);\n setOpen(false);\n };\n\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n className=\"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\"\n >\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">Data</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{display}</span>\n </span>\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div\n role=\"listbox\"\n aria-label=\"Data\"\n className={cx(\n \"absolute top-[calc(100%+8px)] z-30 min-w-[220px] overflow-hidden rounded-card border border-border-default bg-surface p-1 shadow-overlay\",\n align === \"right\" ? \"right-0\" : \"left-0\"\n )}\n >\n <Option label=\"All\" selected={!value} onClick={() => choose(false)} />\n <Option label=\"Final only\" selected={value} onClick={() => choose(true)} hint={FINAL_ONLY_TEXT} />\n </div>\n )}\n </div>\n );\n}\n\nfunction Option({\n label,\n selected,\n onClick,\n hint,\n}: {\n label: string;\n selected: boolean;\n onClick: () => void;\n hint?: string;\n}) {\n const option = (\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n onClick={onClick}\n className={cx(\n \"flex items-center gap-2 rounded-control px-2.5 py-2 text-left text-[13px] transition-colors hover:bg-subtle\",\n hint ? \"flex-1\" : \"w-full\",\n selected ? \"font-semibold text-text-primary\" : \"text-text-secondary\"\n )}\n >\n <Check size={14} aria-hidden=\"true\" className={cx(\"shrink-0 text-brand-primaryAction\", !selected && \"invisible\")} />\n {label}\n </button>\n );\n\n if (!hint) return option;\n\n return (\n <div className=\"flex items-center pr-2.5\">\n {option}\n <InfoTip text={hint} trigger=\"hover\" label={`About ${label}`} />\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Check, ChevronDown } from \"lucide-react\";\n\n/** Joins conditional class fragments -- this package has no clsx/tailwind-merge dependency. */\nfunction cx(...classes: Array<string | false | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens, trims edge hyphens --\n * used for each option's data-testid (matches the convention already used\n * by DateRangeFilter/AdvertiserQuickFilter in this package). */\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\");\n}\n\n/**\n * @pattern SelectFilter\n * @description Single-select filter chip -- the caption-over-value trigger\n * shape shared with AdvertiserQuickFilter/DateRangeFilter, opening a\n * lightweight listbox of plain string options. Portal-rendered to\n * `document.body` so the popover is never clipped by a scrollable ancestor\n * (e.g. inside a modal) -- unlike this package's other chip popovers, none\n * of which are known to sit inside a clipping container today.\n * @tokens rounded-control, rounded-card, border-border-default,\n * border-border-strong, bg-input, bg-surface, shadow-overlay,\n * text-text-primary, text-text-secondary,\n * text-text-tertiary, hover:bg-subtle, hover:text-text-primary,\n * text-brand-primaryAction, focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior The popover is portal-rendered to document.body, so its own DOM\n * node isn't inside the trigger. The outside-click check tests both the\n * trigger and the popover explicitly for that reason -- treating the\n * popover as \"outside\" would close it on every option click before\n * `onChange` ever fires, so nothing would ever get selected. Selecting an\n * option commits immediately and closes -- there's no separate draft/Apply\n * step; Escape and outside-click just close without side effects.\n * @a11y Trigger is a <button>; the popover is role=\"listbox\" with role=\"option\"\n * rows carrying aria-selected. The trigger owns the accessible name via\n * the caption. The popover is not a focus trap and does not move focus on\n * open, so keyboard users tab into it; a consumer rendering it inside\n * another dismissible layer has to sequence the two dismissals itself.\n * @usage\n * ```tsx\n * <SelectFilter caption=\"Rank\" value={rankFilter} onChange={setRankFilter} options={['All', 'VP / Director', 'Manager', 'Coordinator']} />\n * <SelectFilter caption=\"Group by\" value={groupBy} onChange={setGroupBy} options={['Parent', 'Advertiser', 'Brand']} fullWidth testIdPrefix=\"dropdown-group-by\" />\n * ```\n */\nexport interface SelectFilterProps {\n caption: string;\n value: string;\n options: string[];\n onChange: (v: string) => void;\n /** Which edge of the trigger the popover aligns to. */\n align?: \"left\" | \"right\";\n /** Stretch the trigger (and the popover, when true) to fill its container. */\n fullWidth?: boolean;\n /** Extra classes merged onto the trigger button -- e.g. a background\n * override for a filter bar that isn't sitting on a filter-tray canvas. */\n className?: string;\n /**\n * Optional prefix for `data-testid` attributes on the trigger\n * (`${testIdPrefix}-trigger`), the popover (`${testIdPrefix}-popover`),\n * and each option (`${testIdPrefix}-option-<slugified-label>`). Omit\n * entirely for no test-id wiring at all -- added specifically so an\n * existing Playwright suite keyed off hardcoded ids (mr-clientapps'\n * `GroupBySelect`, e.g. `dropdown-group-by-option-parent`) can be re-keyed\n * to this shared component's ids rather than losing its locators outright.\n */\n testIdPrefix?: string;\n}\n\nexport function SelectFilter({\n caption,\n value,\n options,\n onChange,\n align = \"left\",\n fullWidth = false,\n className,\n testIdPrefix,\n}: SelectFilterProps) {\n const [open, setOpen] = useState(false);\n const [pos, setPos] = useState<{ top: number; left: number; width: number } | null>(null);\n const ref = useRef<HTMLDivElement>(null);\n // The popover is portaled to <body>, so it's not a DOM descendant of `ref`.\n // Without checking this too, every option click reads as \"outside\" and\n // closes the popover on mousedown -- before the click that fires onChange\n // ever reaches the (now-unmounted) option button, so selection never sticks.\n const popoverRef = useRef<HTMLDivElement>(null);\n\n const close = useCallback(() => setOpen(false), []);\n\n const reposition = useCallback(() => {\n if (!ref.current) return;\n const r = ref.current.getBoundingClientRect();\n setPos({ top: r.bottom + 8, left: align === \"right\" ? r.right - r.width : r.left, width: r.width });\n }, [align]);\n\n useLayoutEffect(() => {\n if (!open) return;\n reposition();\n }, [open, reposition]);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && close();\n const onClick = (e: MouseEvent) => {\n const t = e.target as Node;\n if (ref.current?.contains(t) || popoverRef.current?.contains(t)) return;\n close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onClick);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"scroll\", reposition, true);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onClick);\n window.removeEventListener(\"resize\", reposition);\n window.removeEventListener(\"scroll\", reposition, true);\n };\n }, [open, close, reposition]);\n\n return (\n <div className={cx(\"relative\", fullWidth && \"w-full\")} ref={ref}>\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-trigger`}\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n className={cx(\n \"flex h-11 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n fullWidth && \"w-full justify-between\",\n className\n )}\n >\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">{caption}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open &&\n pos &&\n createPortal(\n <div\n ref={popoverRef}\n data-testid={testIdPrefix && `${testIdPrefix}-popover`}\n style={{ position: \"fixed\", top: pos.top, left: pos.left, width: fullWidth ? pos.width : undefined }}\n className={cx(\n \"z-[65] flex flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay\",\n !fullWidth && \"w-56\"\n )}\n role=\"listbox\"\n aria-label={caption}\n >\n <div className=\"max-h-[280px] overflow-y-auto p-1\">\n {options.map((o) => {\n const selected = o === value;\n return (\n <button\n key={o}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n data-testid={testIdPrefix && `${testIdPrefix}-option-${slug(o)}`}\n onClick={() => {\n onChange(o);\n close();\n }}\n className=\"flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle\"\n >\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center text-brand-primaryAction\">\n {selected && <Check size={15} strokeWidth={3} />}\n </span>\n <span\n className={cx(\"flex-1 text-[14px]\", selected ? \"font-semibold text-text-primary\" : \"text-text-primary\")}\n >\n {o}\n </span>\n </button>\n );\n })}\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { forwardRef, type ReactNode } from \"react\";\n\n/**\n * @pattern Card\n * @description Layout primitive for grouping content in a bordered, elevated\n * surface. Width is controlled by the parent container, not the Card itself,\n * so it works unchanged as a fixed-width rail item or a grid cell. Applies an\n * interactive hover treatment (deeper shadow) unless `staticCard` is set. An\n * optional `title` (+ `subtitle`/`action`) renders a standard header row and\n * switches the card into a padded content layout, replacing the header/body\n * shell mr-clientapps-insights-studio's own `CardShell` used to hand-roll.\n * @tokens rounded-card, border-border-default, bg-surface, shadow-raised,\n * hover:shadow-overlay, p-card-padding, text-text-primary, text-text-tertiary\n * @behavior Without `title`, children render directly as the card's only\n * content -- no padding is applied, so callers that need a full-bleed image\n * or gradient flush against the card edge (the common case in\n * insights-studio-prototype's rail/grid cards) stay in control of their own\n * inner layout, exactly as before this component grew a `title` prop. With\n * `title`, the header and children are wrapped together in the card's\n * standard padding, matching `CardShell`'s layout so it can be swapped in\n * directly. `staticCard` drops the hover-shadow transition for non-clickable\n * content (a KPI tile, a read-only summary) -- there's nothing to respond to.\n * @variant interactive - Default. Clickable/hoverable content -- deeper\n * shadow on hover signals it responds to the cursor.\n * @variant static - Set `staticCard`. Non-clickable content -- no hover\n * treatment.\n * @usage\n * ```tsx\n * <Card>\n * <h3>Title</h3>\n * <p>Body content</p>\n * </Card>\n * <Card staticCard>Non-interactive content</Card>\n * <Card title=\"Spend trend\" subtitle=\"Last 90 days\" action={<Link to=\"/spend\">View all</Link>}>\n * <SpendChart />\n * </Card>\n * ```\n */\nexport interface CardProps extends Omit<React.HTMLAttributes<HTMLElement>, \"title\"> {\n /** Disable interactive hover treatment (when card isn't clickable). */\n staticCard?: boolean;\n /**\n * Optional header title. Omit it (the default) to keep Card a bare,\n * unpadded surface -- set it to get a title/subtitle/action header row\n * plus the card's standard content padding, matching `CardShell`.\n */\n title?: string;\n /** Shown under `title` in a muted tertiary color. Ignored without `title`. */\n subtitle?: string;\n /** Trailing header content, e.g. a \"View all\" link. Ignored without `title`. */\n action?: ReactNode;\n /** Card body. Rendered edge to edge without `title`; inside the standard padding with it. */\n children?: ReactNode;\n}\n\nexport const Card = forwardRef<HTMLElement, CardProps>(function Card(\n { staticCard, title, subtitle, action, className, children, ...rest },\n ref\n) {\n return (\n <article\n ref={ref}\n className={[\n \"flex h-full flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-raised\",\n // Interactive hover: deeper drop shadow only -- no elevation/transform.\n !staticCard && \"group transition-shadow hover:shadow-overlay\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n {...rest}\n >\n {title ? (\n <div className=\"flex flex-1 flex-col p-card-padding\">\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <h3 className=\"text-[15px] font-semibold leading-snug text-text-primary\">{title}</h3>\n {subtitle && <p className=\"mt-0.5 text-[12px] leading-snug text-text-tertiary\">{subtitle}</p>}\n </div>\n {action && <div className=\"shrink-0 text-text-tertiary\">{action}</div>}\n </div>\n <div className=\"mt-4 flex flex-1 flex-col\">{children}</div>\n </div>\n ) : (\n children\n )}\n </article>\n );\n});\n","import { FilterX } from \"lucide-react\";\n\n/**\n * The one \"no results\" message, shared across every filtered table/list that\n * can end up empty for the same two reasons -- see the component doc below\n * for why they're deliberately not distinguished.\n */\nexport const NO_RESULTS_TITLE = \"No results match your filters\";\nexport const NO_RESULTS_BODY =\n \"Your filters may be too narrow, conflict with each other, or have no activity in this period.\";\n\n/**\n * The body for the active workspace: named while one is active, since its scope\n * bounds the result as much as the filters do. Under \"All data\" (no name) the\n * generic line stands alone.\n */\nexport function noResultsBody(workspaceName?: string | null): string {\n return workspaceName ? `Nothing in the “${workspaceName}” workspace matches. ${NO_RESULTS_BODY}` : NO_RESULTS_BODY;\n}\n\n/** One caller-supplied recovery action, rendered after the two named handlers. */\nexport interface NoResultsAction {\n label: string;\n onClick: () => void;\n /** Rendered as the filled button; every other action renders as the quiet link/button. */\n primary?: boolean;\n}\n\nexport const PRIMARY_ACTION_CLASS =\n \"rounded-control bg-brand-primaryAction px-3.5 py-2 text-[13px] font-semibold text-white transition-colors hover:opacity-90\";\nexport const QUIET_ACTION_CLASS =\n \"rounded-control text-[13px] font-medium text-text-link transition-colors hover:underline focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\";\n\n/**\n * @pattern NoResultsEmptyState\n * @description Guided empty state for a query that returned nothing.\n * Deliberately one state for two causes, because the user can't tell them\n * apart and the fix is the same either way -- loosen the filters or widen the\n * date range: (1) a filter combination that can't match anything, or (2) a\n * valid combination with no activity in the selected period. So the copy\n * names both possibilities instead of asserting one. Renders as a bare\n * stack -- no border, background, or fixed height -- so it can sit directly\n * in a colSpan table cell (or a card, or a chart body) that already owns\n * that chrome, without imposing its own.\n * @tokens bg-subtle, text-text-tertiary, text-base, text-text-primary,\n * text-text-secondary, rounded-control, bg-brand-primaryAction, text-text-link,\n * focus-visible:outline-border-focus\n * @dependencies lucide-react\n * @behavior The Clear button shows when `onClearFilters` is given AND\n * `hasFilters` isn't explicitly `false` -- so a caller can either pass the\n * handler conditionally (only when there's something to clear) or always\n * pass it and gate visibility with `hasFilters` separately; both existing\n * call patterns work unchanged. The Edit button shows whenever\n * `onEditFilters` is given. `actions` appends further caller-defined\n * recovery buttons (e.g. \"Switch workspace\") after the two named ones, for\n * empty states whose fix isn't about filters at all -- primary gets the\n * filled treatment, everything else the quiet one.\n * @a11y The optional action is a real <button> with visible text as its\n * accessible name; the illustration is aria-hidden. Nothing here announces\n * automatically, so a consumer replacing results should manage its own\n * live region if the change needs announcing.\n * @usage\n * ```tsx\n * <NoResultsEmptyState hasFilters={hasFilters} onClearFilters={clearFilters} onEditFilters={openFilterTray} />\n * <NoResultsEmptyState\n * title=\"Properties not set up in this workspace\"\n * body=\"Switch to a workspace that has them defined or create a new one.\"\n * actions={[{ label: 'Switch workspace', onClick: openSwitcher, primary: true }, { label: 'Create workspace', onClick: createNew }]}\n * />\n * ```\n */\nexport interface NoResultsEmptyStateProps {\n /** @default NO_RESULTS_TITLE */\n title?: string;\n /** Replaces the default body wholesale, workspace name included. */\n body?: string;\n /** The active workspace's name, or nothing under \"All data\". Shapes the default body only -- ignored when `body` is given. */\n workspaceName?: string | null;\n /**\n * Explicit override for whether the Clear button can show. Omit to derive\n * it from whether `onClearFilters` was passed; pass `false` to force it\n * hidden even though a handler was given (e.g. the handler exists but\n * nothing is currently applied).\n */\n hasFilters?: boolean;\n onClearFilters?: () => void;\n onEditFilters?: () => void;\n /** Extra recovery actions, rendered in order after Clear/Edit. */\n actions?: NoResultsAction[];\n /**\n * Optional prefix for `data-testid` attributes on the container\n * (`testIdPrefix` itself), the Clear button (`${testIdPrefix}-clear`), and\n * the Edit button (`${testIdPrefix}-edit`). Omit for no test-id wiring.\n * Pass `\"no-results\"` to reproduce mr-clientapps-insights-studio's current\n * fixed ids (`no-results`, `no-results-clear`, `no-results-edit`) exactly.\n */\n testIdPrefix?: string;\n}\n\nexport function NoResultsEmptyState({\n title = NO_RESULTS_TITLE,\n body,\n workspaceName,\n hasFilters,\n onClearFilters,\n onEditFilters,\n actions,\n testIdPrefix,\n}: NoResultsEmptyStateProps) {\n const bodyText = body ?? noResultsBody(workspaceName);\n const showClear = hasFilters !== false && Boolean(onClearFilters);\n const showEdit = Boolean(onEditFilters);\n const hasActions = showClear || showEdit || Boolean(actions && actions.length > 0);\n\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 text-center\" data-testid={testIdPrefix}>\n <span className=\"flex h-11 w-11 items-center justify-center rounded-full bg-subtle text-text-tertiary\">\n <FilterX size={20} aria-hidden=\"true\" />\n </span>\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n <p className=\"max-w-[420px] text-[13px] leading-relaxed text-text-secondary\">{bodyText}</p>\n {hasActions && (\n <div className=\"mt-1 flex flex-col items-center gap-3\">\n {showClear && (\n <button\n type=\"button\"\n onClick={onClearFilters}\n data-testid={testIdPrefix && `${testIdPrefix}-clear`}\n className={PRIMARY_ACTION_CLASS}\n >\n Clear all filters\n </button>\n )}\n {showEdit && (\n <button\n type=\"button\"\n onClick={onEditFilters}\n data-testid={testIdPrefix && `${testIdPrefix}-edit`}\n className={QUIET_ACTION_CLASS}\n >\n Edit filters\n </button>\n )}\n {actions?.map((action, i) => (\n <button\n key={`${i}-${action.label}`}\n type=\"button\"\n onClick={action.onClick}\n className={action.primary ? PRIMARY_ACTION_CLASS : QUIET_ACTION_CLASS}\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { ChevronDown, X } from \"lucide-react\";\n\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface SummaryGroupItemValue {\n id: string;\n name: string;\n /**\n * Secondary line under the name. Takes a node rather than a plain string\n * so a caller can render something richer than static text there -- e.g.\n * mr-clientapps-insights-studio's Account Lists group swaps this for a\n * \"No accounts assigned -- click here to add accounts\" link when a list is\n * empty, which a plain `string` field couldn't hold.\n */\n meta?: React.ReactNode;\n}\n\nexport interface SummaryGroup {\n id: string;\n label: string;\n items: SummaryGroupItemValue[];\n onRemove: (id: string) => void;\n onRemoveAll: () => void;\n /** Nested sub-sections rendered, indented, beneath this group's own items. */\n subGroups?: SummaryGroup[];\n}\n\n/**\n * @pattern WorkspaceSelectedCard\n * @description Sticky recap card listing what each section's picker has\n * added, as collapsible groups with per-item remove and \"Remove all\" --\n * generic over the `SummaryGroup` shape, no domain coupling. Reconciled from\n * two implementations: insights-studio-prototype's generic `SummaryGroup[]`\n * (kept, since it cleanly covers mr-clientapps-insights-studio's own usage\n * too -- that app's fixed `sets`/`accountLists` prop pair is just this same\n * shape with the group list hardcoded at the call site instead of passed\n * in) and mr-clientapps-insights-studio's `SelectedSummary`, whose\n * `wasEmpty`-ref auto-expand tracking turned out to be the correct one (see\n * `@behavior`) and whose `shadow-1` -- not a real `@mediaradar/design-tokens`\n * class, confirmed against the built theme -- pointed at a real, deliberately\n * omitted elevation this card was missing; the local `shadow-1`/`shadow-2`\n * naming maps to this package's `shadow-raised`/`shadow-overlay` respectively\n * (raised: a static card like this one; overlay: a floating popover/menu),\n * not a 1:1 name swap.\n * @tokens rounded-card, border-border-default, bg-surface, shadow-raised,\n * text-text-secondary, text-text-primary, rounded-full, bg-subtle,\n * rounded-control, bg-canvas, hover:bg-subtle, hover:text-text-danger,\n * text-text-link, divide-border-default\n * @dependencies lucide-react\n * @behavior A group auto-expands only on the empty-to-nonempty transition\n * (including via a nested sub-group's items) and auto-collapses when\n * emptied; manual open/close toggles in between are preserved. This is\n * mr-clientapps-insights-studio's `wasEmpty`-ref logic, not\n * insights-studio-prototype's original `prevCount`-comparison one --\n * verified the two differ: the original re-opened a group on ANY item\n * increase, including one added to an already-open or already\n * manually-collapsed nonempty group, silently undoing the user's own\n * collapse. Sub-groups render indented beneath their parent's own items.\n * @a11y The card's toggle is a button reporting aria-expanded, with an aria-\n * label since it renders icon-only. Decorative marks are aria-hidden.\n * @usage\n * ```tsx\n * <WorkspaceSelectedCard groups={[{ id: 'advertisers', label: 'Advertisers', items: selected, onRemove: removeOne, onRemoveAll: clearAll }]} />\n * ```\n */\nexport interface WorkspaceSelectedCardProps {\n groups: SummaryGroup[];\n /**\n * Optional prefix for `data-testid` attributes on each group's toggle\n * (`${testIdPrefix}-group-<group.id>`) and its \"Remove all\" button\n * (`${testIdPrefix}-remove-all-<group.id>`), applied recursively to\n * sub-groups too. Omit for no test-id wiring.\n *\n * NOTE: this does not reproduce mr-clientapps-insights-studio's current\n * fixed ids byte-for-byte -- its container carries a separate, unrelated\n * `workspace-selected-summary` id (this component has no single container\n * element those groups sit inside, by design, so there's nothing to attach\n * an equivalent id to) while its groups use a *different* prefix,\n * `workspace-summary-group-<type>` / `workspace-summary-remove-all-<type>`.\n * A consumer with existing Playwright locators keyed off those exact\n * strings needs to update them, or the caller needs its own id mapping --\n * not attempted here, same as `DateRangeFilter`'s documented preset-slug\n * mismatch.\n */\n testIdPrefix?: string;\n}\n\nexport function WorkspaceSelectedCard({ groups, testIdPrefix }: WorkspaceSelectedCardProps) {\n return (\n <aside className=\"sticky top-4 flex min-w-0 flex-col gap-4 self-start rounded-card border border-border-default bg-surface px-5 pb-5 pt-4 shadow-raised sm:px-6 sm:pb-6\">\n <div className=\"flex flex-col divide-y divide-border-default\">\n {groups.map((g) => (\n <SummaryGroupItem key={g.id} group={g} testIdPrefix={testIdPrefix} />\n ))}\n </div>\n </aside>\n );\n}\n\nfunction SummaryGroupItem({\n group,\n nested = false,\n testIdPrefix,\n}: {\n group: SummaryGroup;\n nested?: boolean;\n testIdPrefix?: string;\n}) {\n const ownCount = group.items.length;\n const subCount = (group.subGroups ?? []).reduce((n, sg) => n + sg.items.length, 0);\n // Auto-expand tracks own items plus any nested sub-group items, so adding\n // e.g. an account list opens the Advertisers section even with no manual\n // picks in Advertisers itself.\n const expandCount = ownCount + subCount;\n const [open, setOpen] = useState(expandCount > 0);\n // Tracks the empty <-> nonempty transition only -- NOT every count change --\n // so adding another item to a group that's already open, or already\n // manually collapsed while nonempty, never forces its open state either\n // way. Emptying it (via remove / remove-all) does collapse it back down.\n const wasEmpty = useRef(expandCount === 0);\n useEffect(() => {\n if (wasEmpty.current && expandCount > 0) setOpen(true);\n else if (expandCount === 0) setOpen(false);\n wasEmpty.current = expandCount === 0;\n }, [expandCount]);\n\n return (\n <div className={nested ? \"\" : \"py-3 first:pt-0 last:pb-0\"}>\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n aria-expanded={open}\n data-testid={testIdPrefix && `${testIdPrefix}-group-${group.id}`}\n className=\"flex w-full min-w-0 items-center gap-2 text-left\"\n >\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cx(\"shrink-0 text-text-secondary transition-transform\", !open && \"-rotate-90\")}\n />\n <span className={cx(\"truncate font-semibold text-text-primary\", nested ? \"text-[12px]\" : \"text-[13px]\")}>\n {group.label}\n </span>\n <span className=\"shrink-0 rounded-full bg-subtle px-1.5 py-0.5 text-[11px] font-semibold text-text-secondary\">\n {ownCount}\n </span>\n </button>\n {open && (\n <div className=\"pt-2.5\">\n {ownCount === 0 && subCount === 0 ? (\n <p className=\"text-[12px] text-text-secondary\">Nothing selected.</p>\n ) : (\n <div className=\"flex flex-col gap-2.5\">\n {ownCount > 0 && (\n <div className=\"flex flex-col gap-1.5\">\n {group.items.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between gap-2 rounded-control border border-border-default bg-canvas px-2 py-1\"\n >\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[12px] text-text-primary\">{item.name}</span>\n {item.meta && <span className=\"block truncate text-[11px] text-text-secondary\">{item.meta}</span>}\n </span>\n <button\n type=\"button\"\n aria-label={`Remove ${item.name}`}\n onClick={() => group.onRemove(item.id)}\n className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-control text-text-secondary hover:bg-subtle hover:text-text-danger\"\n >\n <X size={12} aria-hidden=\"true\" />\n </button>\n </div>\n ))}\n <button\n type=\"button\"\n onClick={group.onRemoveAll}\n data-testid={testIdPrefix && `${testIdPrefix}-remove-all-${group.id}`}\n className=\"mt-0.5 self-start text-[11px] font-medium text-text-link hover:underline\"\n >\n Remove all\n </button>\n </div>\n )}\n {group.subGroups?.map((sg) => (\n <SummaryGroupItem key={sg.id} group={sg} nested testIdPrefix={testIdPrefix} />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","/**\n * Internal helpers shared by the four chart-placeholder patterns\n * (`BarChartPlaceholder`, `PieChartPlaceholder`, `StackedColumnPlaceholder`,\n * `LineChartPlaceholder`). Not itself a pattern, and not exported from the\n * package entry point -- each of the four owns its own `@pattern` JSDoc and\n * its own variant-specific proportions (bar heights, pie seams, column\n * weights, line series); only the axis/legend scaffolding common to more\n * than one of them lives here.\n */\n\n/** Gridline positions as a percentage down the plot area. */\nexport const GRID_ROWS = [0, 25, 50, 75, 100];\n\n/** Blank y-tick widths -- uneven, the way real tick labels differ in length. */\nexport const Y_TICK_WIDTHS = [26, 30, 30, 26, 20];\n\n/** Gutters, matched to the axis sizes the live charts reserve. */\nexport const Y_AXIS_W = 48;\nexport const X_AXIS_H = 22;\n\n/** Blank legend-label widths, cycled -- real names are not all one length. */\nexport const LEGEND_WIDTHS = [58, 44, 66, 50, 38, 62, 46, 54];\n\n/**\n * Axis scaffolding shared by the placeholders whose live charts have axes:\n * dashed gridlines, plus a blank box at every tick position on both axes.\n * `children` is drawn into the plot area, inset by the axis gutters.\n */\nexport function AxisFrame({\n height,\n xTicks,\n children,\n}: {\n height: number;\n /**\n * Blank x-tick boxes to draw. 0 reserves no gutter -- for a live chart\n * whose x-axis carries no labels of its own.\n */\n xTicks: number;\n children?: React.ReactNode;\n}) {\n const gutter = xTicks > 0 ? X_AXIS_H : 0;\n return (\n <div className=\"w-full\" style={{ height }} role=\"presentation\" aria-hidden=\"true\">\n <div className=\"relative h-full w-full\">\n {/* Plot area */}\n <div className=\"absolute inset-y-0 right-0\" style={{ left: Y_AXIS_W, bottom: gutter }}>\n {GRID_ROWS.map((pct) => (\n <div\n key={pct}\n className=\"absolute inset-x-0 border-t border-dashed\"\n style={{ top: `${pct}%`, borderColor: \"var(--mr-color-border-default)\" }}\n />\n ))}\n <div className=\"absolute inset-0\">{children}</div>\n </div>\n\n {/* Blank y-axis ticks, centered on their gridlines */}\n <div className=\"absolute left-0 top-0\" style={{ width: Y_AXIS_W, bottom: gutter }}>\n {GRID_ROWS.map((pct, i) => (\n <div\n key={pct}\n className=\"absolute right-2 h-2 -translate-y-1/2 rounded-xs bg-subtle\"\n style={{ top: `${pct}%`, width: Y_TICK_WIDTHS[i] }}\n />\n ))}\n </div>\n\n {/* Blank x-axis ticks, one per slot */}\n {xTicks > 0 && (\n <div\n className=\"absolute bottom-0 right-0 flex items-center\"\n style={{ left: Y_AXIS_W, height: X_AXIS_H }}\n >\n {Array.from({ length: xTicks }, (_, i) => (\n <div key={i} className=\"flex flex-1 justify-center\">\n <div className=\"h-2 w-full max-w-[26px] rounded-xs bg-subtle\" />\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Blank legend -- a swatch and a name box per entry, with a value box on the\n * right, holding the column the real legend occupies.\n */\nexport function BlankLegend({ rows, reverse = false }: { rows: number; reverse?: boolean }) {\n return (\n <ul\n className={`flex flex-1 justify-center gap-1.5 ${reverse ? \"flex-col-reverse\" : \"flex-col\"}`}\n role=\"presentation\"\n aria-hidden=\"true\"\n >\n {Array.from({ length: rows }, (_, i) => (\n <li key={i} className=\"flex items-center justify-between gap-2\">\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-xs bg-subtle\" />\n <span\n className=\"h-2 rounded-xs bg-subtle\"\n style={{ width: LEGEND_WIDTHS[i % LEGEND_WIDTHS.length] }}\n />\n </span>\n <span className=\"h-2 w-6 rounded-xs bg-subtle\" />\n </li>\n ))}\n </ul>\n );\n}\n","import { AxisFrame } from \"./chart-placeholder-shared\";\n\n/** Descending bar profile -- the shape a ranked spend chart takes. */\nconst BAR_PROFILE = [92, 86, 76, 65, 57, 40, 30, 24, 18, 13];\n\n/**\n * @pattern BarChartPlaceholder\n * @description Neutral, dataless stand-in for a ranked-bar chart --\n * descending bar profile under a blank-labelled axis frame (dashed\n * gridlines, blank y/x-tick boxes), so an unsatisfiable filter still reads\n * as \"a chart belongs here\" rather than a failed load. No real value ever\n * appears (no channel/league names, media types, dollar amounts,\n * percentages, or series colors), and the shape holds the card's layout\n * steady so nothing jumps when real data arrives.\n * @tokens bg-subtle, border-border-default, rounded-xs\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout, since none of the boxes carry real\n * content for assistive tech to announce. The bar count and profile are a\n * fixed shape, not driven by `height`.\n * @a11y role=\"presentation\" with aria-hidden marks: a visual stand-in with no\n * data, deliberately invisible to assistive tech. Don't add a caption\n * expecting it to be announced.\n * @usage\n * ```tsx\n * <BarChartPlaceholder />\n * <BarChartPlaceholder height={180} />\n * ```\n */\nexport interface BarChartPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n}\n\nexport function BarChartPlaceholder({ height = 220 }: BarChartPlaceholderProps) {\n return (\n <AxisFrame height={height} xTicks={BAR_PROFILE.length}>\n <div className=\"flex h-full w-full items-end gap-2\">\n {BAR_PROFILE.map((pct, i) => (\n <div key={i} className=\"flex-1 rounded-t-[3px] bg-subtle\" style={{ height: `${pct}%` }} />\n ))}\n </div>\n </AxisFrame>\n );\n}\n","import { AxisFrame } from \"./chart-placeholder-shared\";\n\n/**\n * Four trend paths as y-percentages down the plot (so a lower number sits\n * higher on the chart), sampled at ten evenly spaced x positions. Four\n * rather than a higher real series count: enough to read as a multi-series\n * trend, few enough that same-colored paths don't turn to mush.\n */\nconst LINE_SERIES = [\n [58, 52, 55, 41, 45, 33, 36, 25, 28, 17],\n [74, 71, 66, 68, 59, 61, 54, 56, 48, 45],\n [40, 44, 37, 41, 34, 38, 31, 34, 27, 26],\n [86, 82, 84, 77, 79, 71, 73, 66, 68, 61],\n];\n\n/** Index at which the solid line hands off to the dashed forecast tail. */\nconst LINE_FORECAST_FROM = 7;\n\n/**\n * @pattern LineChartPlaceholder\n * @description Neutral, dataless stand-in for a multi-series trend chart --\n * four grey paths over the shared axis frame, each with a solid-then-dashed\n * handoff for the live chart's forecast tail, and a point at every sample.\n * Points are positioned rather than drawn in the SVG: the plot stretches to\n * the card, and a stretched `<circle>` would go oval. Same no-results use\n * as `BarChartPlaceholder` -- no real value ever appears, and the shape\n * holds the card's layout steady so nothing jumps when real data arrives.\n * Paths and points share the `bg-subtle` fill of the axis labels, so the\n * whole placeholder reads as one tint, the way the bars do.\n * @tokens bg-subtle, border-border-default, rounded-xs\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout (inherited from `AxisFrame`). The series\n * count and shapes are fixed; `height` is the only variable.\n * @a11y role=\"presentation\" with aria-hidden marks: a visual stand-in with no\n * data, deliberately invisible to assistive tech. Don't add a caption\n * expecting it to be announced.\n * @usage\n * ```tsx\n * <LineChartPlaceholder />\n * <LineChartPlaceholder height={200} />\n * ```\n */\nexport interface LineChartPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n}\n\nexport function LineChartPlaceholder({ height = 280 }: LineChartPlaceholderProps) {\n const toPath = (pts: number[], from: number, to: number) =>\n pts\n .slice(from, to)\n .map((y, i) => `${((i + from) / (pts.length - 1)) * 100},${y}`)\n .join(\" \");\n\n return (\n <AxisFrame height={height} xTicks={LINE_SERIES[0].length}>\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" className=\"absolute inset-0 h-full w-full\">\n {LINE_SERIES.map((pts, s) => (\n <g key={s}>\n <polyline\n points={toPath(pts, 0, LINE_FORECAST_FROM + 1)}\n fill=\"none\"\n stroke=\"var(--mr-color-subtle)\"\n strokeWidth=\"2\"\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <polyline\n points={toPath(pts, LINE_FORECAST_FROM, pts.length)}\n fill=\"none\"\n stroke=\"var(--mr-color-subtle)\"\n strokeWidth=\"2\"\n strokeDasharray=\"5 4\"\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n ))}\n </svg>\n {LINE_SERIES.map((pts, s) =>\n pts.map((y, i) => (\n <div\n key={`${s}-${i}`}\n className=\"absolute h-1.5 w-1.5 -translate-x-1/2 -translate-y-1/2 rounded-full\"\n style={{\n left: `${(i / (pts.length - 1)) * 100}%`,\n top: `${y}%`,\n backgroundColor: \"var(--mr-color-subtle)\",\n }}\n />\n ))\n )}\n </AxisFrame>\n );\n}\n","import { BlankLegend } from \"./chart-placeholder-shared\";\n\n/** Uneven seam angles (degrees, clockwise from 12 o'clock) -- a share split. */\nconst PIE_SEAMS = [0, 115, 180, 230, 262, 288, 310, 332];\n\n/**\n * @pattern PieChartPlaceholder\n * @description Neutral, dataless stand-in for a pie chart -- a grey disc\n * seamed where slices would fall, beside a blank legend. No axis, matching\n * the live pie it stands in for. Same no-results use as\n * `BarChartPlaceholder`: an unsatisfiable filter reads as \"a chart belongs\n * here\" rather than a failed load, with no real value (names, media types,\n * dollar amounts, percentages, series colors) ever appearing.\n * @tokens bg-subtle, bg-surface, rounded-xs\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout. `legendRows` controls the blank legend\n * only; the disc's seam count is a fixed shape. Seams are cut in the\n * card's `bg-surface` color, as `StackedColumnPlaceholder`'s bands are.\n * @a11y role=\"presentation\" with aria-hidden marks: it is a visual stand-in with\n * no data, deliberately invisible to assistive tech. Don't add a caption\n * expecting it to be announced.\n * @usage\n * ```tsx\n * <PieChartPlaceholder />\n * <PieChartPlaceholder legendRows={4} />\n * ```\n */\nexport interface PieChartPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n /** Number of blank legend rows to render beside the disc. */\n legendRows?: number;\n}\n\nexport function PieChartPlaceholder({ height = 220, legendRows = 8 }: PieChartPlaceholderProps) {\n const r = 45;\n return (\n <div className=\"flex w-full items-center gap-3\" style={{ height }} role=\"presentation\" aria-hidden=\"true\">\n <div className=\"flex h-full items-center justify-center\" style={{ width: \"60%\" }}>\n <svg viewBox=\"0 0 100 100\" className=\"h-full\" style={{ aspectRatio: \"1 / 1\" }}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"var(--mr-color-subtle)\" />\n {PIE_SEAMS.map((deg) => {\n const rad = ((deg - 90) * Math.PI) / 180;\n return (\n <line\n key={deg}\n x1=\"50\"\n y1=\"50\"\n x2={50 + r * Math.cos(rad)}\n y2={50 + r * Math.sin(rad)}\n stroke=\"var(--mr-color-surface)\"\n strokeWidth=\"1\"\n />\n );\n })}\n </svg>\n </div>\n <BlankLegend rows={legendRows} />\n </div>\n );\n}\n","import { AxisFrame, BlankLegend } from \"./chart-placeholder-shared\";\n\n/**\n * Relative band weights for a 100% stacked column, top to bottom. Sliced to\n * one per legend entry and normalized, so the column carries exactly the\n * segments the legend beside it lists -- the way the live chart does.\n */\nconst COLUMN_WEIGHTS = [20, 30, 15, 35, 24, 12, 28, 18];\n\nfunction columnBands(count: number) {\n const weights = Array.from({ length: count }, (_, i) => COLUMN_WEIGHTS[i % COLUMN_WEIGHTS.length]);\n const total = weights.reduce((a, b) => a + b, 0);\n return weights.map((w) => (w / total) * 100);\n}\n\n/**\n * @pattern StackedColumnPlaceholder\n * @description Neutral, dataless stand-in for a 100% stacked column -- a\n * single banded column beside a blank legend. `axis` follows the live card\n * it stands in for: a share-of-total chart plotting on a 0-100% axis passes\n * `axis`, a bare stack with no scale (e.g. a share-of-voice column) omits\n * it. Same no-results use as `BarChartPlaceholder` -- no real value ever\n * appears, and the shape holds the card's layout steady.\n * @tokens bg-subtle, bg-surface, border-border-default, rounded-control\n * @behavior Purely presentational -- `role=\"presentation\"` and\n * `aria-hidden=\"true\"` throughout. Band seams are 1px gaps in the card's\n * `bg-surface` color rather than a border tone: a `border-border-default`\n * seam disappears on the `bg-subtle` fill, and `border-border-strong` reads\n * darker than the rest of the placeholder. Legend rows are reversed (bottom-up) when `axis`\n * is off, matching a bare stack's usual bottom-anchored reading order.\n * @a11y role=\"presentation\" with aria-hidden marks: a visual stand-in with no\n * data, deliberately invisible to assistive tech.\n * @usage\n * ```tsx\n * <StackedColumnPlaceholder />\n * <StackedColumnPlaceholder axis />\n * ```\n */\nexport interface StackedColumnPlaceholderProps {\n /** Chart height in pixels. */\n height?: number;\n /** Column width in pixels. */\n width?: number;\n /** Number of bands (and matching blank legend rows). */\n legendRows?: number;\n /** Wrap the column in a 0-100% axis frame, matching a live share-of-total chart. */\n axis?: boolean;\n}\n\nexport function StackedColumnPlaceholder({\n height = 220,\n width = 96,\n legendRows = 4,\n axis = false,\n}: StackedColumnPlaceholderProps) {\n const column = (\n <div className=\"flex h-full flex-col overflow-hidden rounded-control bg-subtle\" style={{ width }}>\n {columnBands(legendRows).map((pct, i) => (\n <div\n key={i}\n style={{\n height: `${pct}%`,\n /* A gap in the card's color, not a border tone: border-default\n disappears on the subtle fill, border-strong reads darker. */\n borderTop: i === 0 ? undefined : \"1px solid var(--mr-color-surface)\",\n }}\n />\n ))}\n </div>\n );\n return (\n <div className=\"flex w-full gap-4\" style={{ height }} role=\"presentation\" aria-hidden=\"true\">\n {axis ? (\n <div style={{ width: \"55%\" }}>\n <AxisFrame height={height} xTicks={0}>\n <div className=\"flex h-full items-stretch justify-center\">{column}</div>\n </AxisFrame>\n </div>\n ) : (\n <div className=\"flex items-stretch py-1\">{column}</div>\n )}\n <BlankLegend rows={legendRows} reverse={!axis} />\n </div>\n );\n}\n","\"use client\";\n\nimport { useEffect, useId, useLayoutEffect, useRef, useState, type ReactNode, type RefObject, type TransitionEvent } from \"react\";\nimport { createPortal } from \"react-dom\";\n\n/** Joins truthy class fragments -- a local stand-in so this package doesn't\n * pull in a classnames dependency for one conditional class. */\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/** The bubble's real opacity-transition length in ms, read from its computed\n * style rather than hard-coded, so the unmount fallback timer can never\n * disagree with the `--mr-motion-duration-interactive` token. 0 when there is\n * no transition to wait for: reduced motion (the OS setting, or the\n * `motion-reduce:transition-none` class it drives), or a consumer whose\n * design-tokens doesn't define the variable -- an unresolved `var()` there\n * computes to 0s, so it degrades to the old instant hide rather than\n * stranding the bubble. */\nfunction exitDurationMs(el: HTMLElement): number {\n if (typeof window.matchMedia === \"function\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return 0;\n const cs = window.getComputedStyle(el);\n if (cs.transitionProperty === \"none\") return 0;\n const toMs = (v: string) => {\n const n = parseFloat(v);\n if (!Number.isFinite(n)) return 0;\n return v.trim().endsWith(\"ms\") ? n : n * 1000;\n };\n const durations = cs.transitionDuration.split(\",\").map(toMs);\n const delays = cs.transitionDelay.split(\",\").map(toMs);\n return Math.max(0, ...durations.map((d, i) => d + (delays[i] ?? delays[0] ?? 0)));\n}\n\n/**\n * @pattern Tooltip\n * @description Portalled hover/focus tooltip. Two ways to attach a trigger:\n * wrap `children` (the default -- an inline trigger, e.g. a truncated table\n * cell or a chart legend entry), or pass `anchorRef` for an element that\n * already needs its own ref, or where wrapping in an extra inline box would\n * disturb layout (an icon-only collapsed nav rail, for example) -- the two\n * are mutually exclusive ways of specifying the trigger, and `children` is\n * ignored when `anchorRef` is set. Positioned `fixed` from the trigger's\n * bounding rect and rendered through a portal to `document.body`, so it\n * escapes both `overflow` clipping inside scrollable panels and the broken\n * `fixed` containing block a transformed ancestor creates.\n * @tokens rounded-control, border-border-default, bg-surface, shadow-overlay,\n * text-text-primary, bg-text-primary, text-surface,\n * duration-(--mr-motion-duration-interactive)\n * @variant surface - Default. Themed surface/border bubble -- matches the\n * Recharts chart tooltips this was originally built for.\n * @variant inverted - Solid dark pill (no border) -- for a tooltip sitting\n * over a nav rail or other icon-only surface, where the themed surface bubble\n * doesn't read as clearly against a busy background.\n * @behavior Shows on hover and on keyboard focus (so it stays reachable\n * without a pointer) after `delay` ms (0 = immediate, the default). Fades in\n * and out (opacity, `ease-in-out`, over the sys\n * `--mr-motion-duration-interactive` token -- 200ms today); the bubble stays\n * mounted through the fade-out and is removed from the DOM once it ends.\n * Under `prefers-reduced-motion: reduce` there is no fade: it appears and is\n * removed instantly. The hide starts on mouseleave/blur, cancelling a pending\n * delayed show if it hasn't fired yet -- except in `interactive` mode, which\n * delays the hide briefly so the pointer can travel from the trigger into the\n * tooltip's own content. Re-hovering (or re-focusing) the trigger while the\n * bubble is still fading out reverses the fade from where it is, without\n * waiting out `delay` again, since it is already on screen; so does moving\n * the pointer back into an `interactive` bubble. A non-interactive bubble is\n * `pointer-events-none` throughout, fade-out included, so it never\n * intercepts clicks meant for what sits under it. Pass `whenTruncated` to\n * only surface it once the trigger's content\n * is actually clipped by ellipsis (`scrollWidth > clientWidth`). `placement`\n * 'top'/'bottom' centre (or `align=\"start\"` left-align) on the trigger;\n * 'right' centres vertically beside the anchor and 'bottom-end' hangs below,\n * right-aligned to the anchor's right edge -- both meant for `anchorRef`\n * anchors near the viewport's right edge, where a centred box would run\n * off-screen or read awkwardly beside a narrow icon.\n * @a11y Renders role=\"tooltip\" and is wired to its anchor by aria-describedby,\n * so the anchor must exist and keep a stable id. It describes rather than\n * labels: it is announced in addition to the anchor's own name, not\n * instead of it, so never put the only label for a control in here.\n * @usage\n * ```tsx\n * <Tooltip label=\"Full advertiser name\" whenTruncated>\n * <span className=\"truncate\">{name}</span>\n * </Tooltip>\n *\n * const ref = useRef<HTMLButtonElement>(null);\n * <button ref={ref}>Sports</button>\n * <Tooltip label=\"Sports\" anchorRef={ref} placement=\"right\" delay={500} variant=\"inverted\" />\n * ```\n */\nexport interface TooltipProps {\n /** Tooltip content shown on hover/focus. */\n label: ReactNode;\n /** The trigger content, wrapped inline. Omit when using `anchorRef`. */\n children?: ReactNode;\n /**\n * Attach to an existing element instead of wrapping `children` in a\n * trigger span -- see the pattern description. When set, `children` /\n * `className` / `whenTruncated` all still apply to that element (its\n * `scrollWidth`/`clientWidth` drive `whenTruncated`), just without this\n * component rendering a wrapping element of its own.\n */\n anchorRef?: RefObject<HTMLElement | null>;\n /** Classes for the inline trigger wrapper (e.g. `truncate`, `min-w-0`). Ignored with `anchorRef`. */\n className?: string;\n /**\n * Only reveal the tooltip when the trigger's content is actually clipped by\n * ellipsis (`scrollWidth > clientWidth`). Off by default -- the tooltip always\n * shows.\n */\n whenTruncated?: boolean;\n /**\n * When true, the tooltip accepts pointer events so it can contain links and\n * other interactive content.\n */\n interactive?: boolean;\n /**\n * Which side of the trigger to render on. 'top' (default) / 'bottom'\n * centre on the trigger (or left-align with `align=\"start\"`). 'right' /\n * 'bottom-end' are for an `anchorRef` anchor -- see the pattern description.\n */\n placement?: \"top\" | \"bottom\" | \"right\" | \"bottom-end\";\n /**\n * How the box lines up with the trigger horizontally, for 'top'/'bottom'\n * placement only. \"center\" (the default) centres it; \"start\" puts its left\n * edge on the trigger so it grows rightward, which reads better for a small\n * icon sitting beside the text it describes -- a centred box there hangs\n * out over the content to the left.\n */\n align?: \"center\" | \"start\";\n /**\n * Hover delay in ms before the tooltip appears. 0 (default) shows\n * immediately. A collapsed nav rail passes 500 so a fast mouse pass over\n * several icons doesn't flash a tooltip per icon.\n */\n delay?: number;\n /** 'surface' (default) or 'inverted' -- see the pattern description. */\n variant?: \"surface\" | \"inverted\";\n /** Optional prefix for a `data-testid` on the floating tooltip bubble. */\n testIdPrefix?: string;\n}\n\nexport function Tooltip({\n label,\n children,\n anchorRef,\n className,\n whenTruncated = false,\n interactive = false,\n placement = \"top\",\n align = \"center\",\n delay = 0,\n variant = \"surface\",\n testIdPrefix,\n}: TooltipProps) {\n const [anchor, setAnchor] = useState<{ top: number; left: number; width: number; height: number; bottom: number; right: number } | null>(null);\n // The floating box's actual rendered width, measured post-mount. `null` until then --\n // that's what keeps the box hidden for a frame instead of flashing at a guessed\n // position (see the layout effect below).\n const [boxWidth, setBoxWidth] = useState<number | null>(null);\n const ref = useRef<HTMLSpanElement>(null);\n const boxRef = useRef<HTMLSpanElement>(null);\n const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const showTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n // Fallback for the exit fade: unmounts the bubble if `transitionend` never\n // arrives (a transition interrupted by a style change, or a hidden tab).\n const exitTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n // `shown` drives the opacity class; `anchor != null` is \"mounted\". They\n // differ during a fade: mounted but not shown while fading out, and for the\n // frame before a fresh box is measured. The refs mirror intent and mount\n // for the handlers, which in `anchorRef` mode are attached once and would\n // otherwise read stale state.\n const [shown, setShown] = useState(false);\n const openRef = useRef(false);\n const mountedRef = useRef(false);\n const id = useId();\n\n const clearHideTimer = () => {\n if (hideTimer.current) {\n clearTimeout(hideTimer.current);\n hideTimer.current = null;\n }\n };\n const clearShowTimer = () => {\n if (showTimer.current) {\n clearTimeout(showTimer.current);\n showTimer.current = null;\n }\n };\n const clearExitTimer = () => {\n if (exitTimer.current) {\n clearTimeout(exitTimer.current);\n exitTimer.current = null;\n }\n };\n\n useEffect(\n () => () => {\n clearHideTimer();\n clearShowTimer();\n clearExitTimer();\n },\n []\n );\n\n const reveal = () => {\n const el = anchorRef ? anchorRef.current : ref.current;\n if (!el) return;\n if (whenTruncated && el.scrollWidth <= el.clientWidth) return;\n clearExitTimer();\n openRef.current = true;\n const r = el.getBoundingClientRect();\n // A fresh mount stays hidden until measured (see the layout effect). One\n // still fading out keeps its measured width, so reviving it never\n // flashes it hidden.\n if (!mountedRef.current) setBoxWidth(null);\n mountedRef.current = true;\n // A new object every time, so the layout effect re-runs and flips `shown`.\n setAnchor({ top: r.top, left: r.left, width: r.width, height: r.height, bottom: r.bottom, right: r.right });\n if (anchorRef) el.setAttribute(\"aria-describedby\", id);\n };\n\n const show = () => {\n clearHideTimer();\n clearShowTimer();\n // Already on screen (mid fade-out): reverse it now rather than making the\n // user wait out `delay` for something they can already see.\n if (delay > 0 && !mountedRef.current) {\n showTimer.current = setTimeout(reveal, delay);\n } else {\n reveal();\n }\n };\n\n // End of the exit fade: actually remove the bubble. A no-op if a re-hover\n // revived it in the meantime.\n const unmount = () => {\n clearExitTimer();\n if (openRef.current || !mountedRef.current) return;\n mountedRef.current = false;\n setAnchor(null);\n setBoxWidth(null);\n if (anchorRef?.current) anchorRef.current.removeAttribute(\"aria-describedby\");\n };\n\n // Starts the exit fade. The bubble stays mounted until its opacity\n // transition ends (onTransitionEnd below), with a timer as a fallback.\n const hideNow = () => {\n clearShowTimer();\n clearHideTimer();\n openRef.current = false;\n if (!mountedRef.current) return;\n setShown(false);\n clearExitTimer();\n const ms = boxRef.current ? exitDurationMs(boxRef.current) : 0;\n if (ms === 0) {\n unmount();\n return;\n }\n exitTimer.current = setTimeout(unmount, ms + 50);\n };\n\n // Pointer entered an interactive bubble: cancel a pending hide, and revive\n // it if it had already started fading out.\n const keepOpen = () => {\n clearHideTimer();\n if (openRef.current || !mountedRef.current) return;\n clearExitTimer();\n openRef.current = true;\n setShown(true);\n };\n\n const onBoxTransitionEnd = (e: TransitionEvent<HTMLSpanElement>) => {\n if (e.target !== e.currentTarget || e.propertyName !== \"opacity\") return;\n if (!openRef.current) unmount();\n };\n\n // The floating label lives in a portal (separate DOM subtree), so for interactive\n // tooltips leaving the trigger would hide it before the pointer reaches the content.\n // Delay the hide so the pointer can travel across the gap; the content cancels it.\n const hide = () => {\n clearShowTimer();\n if (!interactive) {\n hideNow();\n return;\n }\n clearHideTimer();\n hideTimer.current = setTimeout(hideNow, 120);\n };\n\n // anchorRef mode: this component renders no trigger element of its own, so\n // the show/hide handlers attach directly to the caller's element instead of\n // JSX event props. Also wires keyboard focus, which the original NavTooltip\n // (mouse-only addEventListener) didn't -- kept reachable without a pointer,\n // matching every other hover-trigger component in this package.\n useEffect(() => {\n if (!anchorRef) return;\n const el = anchorRef.current;\n if (!el) return;\n el.addEventListener(\"mouseenter\", show);\n el.addEventListener(\"mouseleave\", hide);\n el.addEventListener(\"focus\", show);\n el.addEventListener(\"blur\", hide);\n return () => {\n el.removeEventListener(\"mouseenter\", show);\n el.removeEventListener(\"mouseleave\", hide);\n el.removeEventListener(\"focus\", show);\n el.removeEventListener(\"blur\", hide);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [anchorRef, placement, delay]);\n\n // Measured once the box mounts at its natural size, so the horizontal clamp below\n // reflects real content width rather than the max-w-xs (320px) ceiling.\n // Measuring also forces a style recalc with a fresh box at opacity-0, so\n // flipping `shown` right after starts a real fade-in instead of the box\n // appearing at full opacity on its first paint.\n useLayoutEffect(() => {\n if (!anchor) return;\n const el = boxRef.current;\n if (!el) return;\n setBoxWidth(el.getBoundingClientRect().width);\n if (openRef.current) setShown(true);\n }, [anchor, label]);\n\n const margin = 8;\n let style: { top: number; left?: number; right?: number } = { top: 0, left: 0 };\n let translate = \"\";\n if (anchor) {\n if (placement === \"right\") {\n style = { top: anchor.top + anchor.height / 2, left: anchor.right + 8 };\n translate = \"-translate-y-1/2\";\n } else if (placement === \"bottom-end\") {\n style = { top: anchor.bottom + 8, right: window.innerWidth - anchor.right };\n } else {\n const w = boxWidth ?? anchor.width;\n const desired = align === \"start\" ? anchor.left : anchor.left + anchor.width / 2 - w / 2;\n const left = Math.min(Math.max(desired, margin), Math.max(margin, window.innerWidth - w - margin));\n style = { left, top: placement === \"bottom\" ? anchor.bottom : anchor.top };\n translate = placement === \"bottom\" ? \"translate-y-2\" : \"-translate-y-[calc(100%+8px)]\";\n }\n }\n\n const floating =\n anchor != null && typeof document !== \"undefined\"\n ? createPortal(\n <span\n ref={boxRef}\n role=\"tooltip\"\n id={id}\n data-testid={testIdPrefix && `${testIdPrefix}-tooltip`}\n style={{ top: style.top, left: style.left, right: style.right, visibility: boxWidth == null ? \"hidden\" : \"visible\" }}\n onMouseEnter={interactive ? keepOpen : undefined}\n onMouseLeave={interactive ? hide : undefined}\n onTransitionEnd={onBoxTransitionEnd}\n // z-[90]: deliberately an arbitrary value, not @mediaradar/design-\n // tokens' semantic z-tooltip (1200) -- same reasoning as InfoTip's:\n // this portals to document.body, becoming a sibling of any open\n // dialog rather than a child of it, and the real z-index scale a\n // consuming app uses for its own modals/toasts can't be assumed\n // from here. 90 sits above a z-[80] modal/menu layer and below a\n // z-[100] toast layer, confirmed against mr-clientapps' own scale\n // (see InfoTip). Also replaces this component's own two source\n // z-index values -- Tooltip.tsx already used this same z-[90];\n // NavTooltip's z-60 had no such documented reasoning behind it.\n className={cx(\n \"fixed z-[90] w-max max-w-xs whitespace-normal break-words px-2.5 py-1.5 text-xs leading-snug\",\n // Fade in/out. The sys duration token rather than a ref one:\n // it is what Button's hover/press transition uses, and a\n // tooltip's fade is the same kind of interactive feedback.\n // design-tokens has no in-out curve (ease-interactive is the\n // decelerating \"standard\" curve), so ease-in-out is Tailwind's.\n \"transition-opacity duration-(--mr-motion-duration-interactive) ease-in-out motion-reduce:transition-none\",\n shown ? \"opacity-100\" : \"opacity-0\",\n // Non-interactive: never a pointer target, fade-out included.\n interactive ? \"pointer-events-auto\" : \"pointer-events-none\",\n variant === \"inverted\" ? \"rounded-control bg-text-primary text-surface\" : \"rounded-control border border-border-default bg-surface text-text-primary shadow-overlay\",\n translate\n )}\n >\n {label}\n </span>,\n document.body\n )\n : null;\n\n if (anchorRef) return floating;\n\n return (\n <span\n ref={ref}\n className={className}\n onMouseEnter={show}\n onMouseLeave={hide}\n onFocus={show}\n onBlur={hide}\n aria-describedby={anchor ? id : undefined}\n >\n {children}\n {floating}\n </span>\n );\n}\n","/**\n * @pattern AdvertiserNoResults\n * @description Shown when a search-first picker's search returns nothing --\n * gives an actionable next step rather than just a bare \"no results\"\n * message. Named for its original (and still primary) use across\n * `insights-studio-prototype`'s three advertiser-search filter trays\n * (Creative Intel, Publisher, Sports), but the `hint` prop makes it reusable\n * for any other search-first dimension. Distinct from the more general\n * `NoResultsEmptyState` (a whole-board \"no results match your filters\"\n * state) -- this one is scoped to a single search box returning nothing,\n * inline within a picker's option list.\n * @tokens text-text-primary, text-text-tertiary\n * @usage\n * ```tsx\n * <AdvertiserNoResults query={query} />\n * <AdvertiserNoResults query={query} hint=\"Try a different spelling, or switch the Agency Type.\" />\n * ```\n */\nexport interface AdvertiserNoResultsProps {\n /** The search term that returned nothing. */\n query: string;\n /** The actionable next step under the message. */\n hint?: string;\n}\n\nexport function AdvertiserNoResults({\n query,\n hint = \"Try checking your spelling or searching for a broader brand name.\",\n}: AdvertiserNoResultsProps) {\n return (\n <div className=\"flex flex-col items-center gap-1.5 px-4 py-8 text-center\">\n <p className=\"text-[13px] font-medium text-text-primary\">No results found for &ldquo;{query}&rdquo;</p>\n <p className=\"text-[12px] leading-snug text-text-tertiary\">{hint}</p>\n </div>\n );\n}\n","import { ListChecks } from \"lucide-react\";\n\n/**\n * @pattern SelectAllVisible\n * @description \"Select all visible\" row for a search-first picker's result\n * list -- only render it once the caller decides the visible result set is\n * long enough to warrant it (`insights-studio-prototype`'s three advertiser-\n * search filter trays all gate it behind a 5-result threshold; mr-clientapps'\n * `ScopedSearchSection` uses the identical threshold and copy for its own\n * scoped search sections). Communicates how many are visible and toggles\n * between \"Select all\" and \"Deselect\" based on `allSelected`.\n * @tokens rounded-control, text-text-link, hover:bg-subtle\n * @dependencies lucide-react\n * @a11y A plain <button>, not a checkbox -- it performs a bulk action rather\n * than holding a checked state, so it deliberately carries no\n * role=\"checkbox\" or aria-checked. Its icon is aria-hidden and the visible\n * text is the accessible name.\n * @usage\n * ```tsx\n * {results.length > 5 && (\n * <SelectAllVisible count={results.length} allSelected={allSelected} onToggle={toggleAll} />\n * )}\n * ```\n */\nexport interface SelectAllVisibleProps {\n /** Number of currently visible results. */\n count: number;\n /** Whether every visible result is already selected. */\n allSelected: boolean;\n onToggle: () => void;\n /** Optional prefix for a `data-testid` on the row. */\n testIdPrefix?: string;\n}\n\nexport function SelectAllVisible({ count, allSelected, onToggle, testIdPrefix }: SelectAllVisibleProps) {\n return (\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-select-all-visible`}\n onClick={onToggle}\n className=\"flex w-full items-center gap-2 rounded-control px-2 py-1.5 text-left text-[12px] font-semibold text-text-link transition-colors hover:bg-subtle\"\n >\n <ListChecks size={14} aria-hidden=\"true\" />\n {allSelected ? `Deselect ${count} visible` : `Select all ${count} visible`}\n </button>\n );\n}\n","import { ChevronDown } from \"lucide-react\";\n\n/** Joins truthy class fragments -- a local stand-in so this package doesn't\n * pull in a classnames dependency for one conditional class. */\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/**\n * @pattern SelectedSection\n * @description Collapsible \"Selected (n)\" container for a search-first\n * picker. Selections can pile up and crowd out the live search results, so\n * the user can fold them away to refocus on the search. Controlled so the\n * parent can auto-collapse it (e.g. when the search is cleared, or jointly\n * with a sibling \"parked\" section) -- `insights-studio-prototype`'s three\n * advertiser-search filter trays all drive `open` this way. The caller\n * renders each selected row itself as `children` rather than this component\n * owning row markup: the three real call sites render genuinely different\n * row content (plain rows, opacity-dimmed \"parked\" rows, per-tray custom\n * columns), so a fixed row shape would have forced a compromise none of them\n * need. Self-hides at `count === 0` so a caller can render it unconditionally.\n * @tokens rounded-control, text-text-tertiary, hover:text-text-primary\n * @dependencies lucide-react\n * @a11y The disclosure header is a button reporting aria-expanded, and the\n * chevron is aria-hidden. It is a disclosure, not a selection control --\n * the rows inside own their own semantics.\n * @usage\n * ```tsx\n * <SelectedSection count={selected.length} open={open} onToggle={() => setOpen((o) => !o)}>\n * {selected.map((s) => <Row key={s.id} item={s} />)}\n * </SelectedSection>\n * ```\n */\nexport interface SelectedSectionProps {\n count: number;\n open: boolean;\n onToggle: () => void;\n /** The caller renders each selected row itself. */\n children: React.ReactNode;\n /** Optional prefix for a `data-testid` on the toggle button. */\n testIdPrefix?: string;\n}\n\nexport function SelectedSection({ count, open, onToggle, children, testIdPrefix }: SelectedSectionProps) {\n if (count === 0) return null;\n return (\n <div className=\"flex flex-col\">\n <button\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-selected-toggle`}\n onClick={onToggle}\n aria-expanded={open}\n className=\"flex w-full items-center gap-1.5 rounded-control px-2 py-1 text-left text-[11px] font-semibold uppercase tracking-wide text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <ChevronDown size={13} aria-hidden=\"true\" className={cx(\"transition-transform\", !open && \"-rotate-90\")} />\n Selected ({count})\n </button>\n {open && <div className=\"flex flex-col gap-0.5\">{children}</div>}\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Search, Plus, Info, ChevronRight, ChevronDown, Check, List, Loader2 } from \"lucide-react\";\nimport { CheckBox } from \"./CheckBox\";\n\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/** Lowercases, strips non-alphanumerics to hyphens, trims edge hyphens -- used for data-testid slugs. */\nfunction slug(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/(^-|-$)/g, \"\");\n}\n\nexport interface PickerRow {\n id: string;\n name: string;\n children?: PickerRow[];\n}\n\nexport interface PickerColumn<T extends PickerRow> {\n key: string;\n header: string;\n render: (row: T) => ReactNode;\n className?: string;\n}\n\nexport interface PickerFilter<T extends PickerRow> {\n label: string;\n options: string[];\n /** Returns the row's value for this filter (matched against options). */\n value: (row: T) => string | undefined;\n}\n\n/** The subset of an account-list record this component actually renders in\n * its \"Account lists\" tab -- a caller's own richer type (with members,\n * createdBy, etc.) is passed in as-is; only these fields are read. */\nexport interface SelectionPickerAccountList {\n id: string;\n name: string;\n /** Number of accounts currently in the list. */\n count: number;\n /** Entity types represented in the list, for a quick descriptive line. */\n entityTypes: string[];\n updatedAt: string;\n}\n\nexport interface SelectionPickerProps<T extends PickerRow> {\n /** Full catalog to search/filter over client-side. Ignored when `results`\n * is given instead -- that's the async/paginated mode, see `results`. */\n catalog?: T[];\n selected: T[];\n onChange: (next: T[]) => void;\n columns: PickerColumn<T>[];\n /** First filter is rendered as the primary entity-type group. */\n filters: PickerFilter<T>[];\n searchPlaceholder?: string;\n /** Optional mock drill-down: returns child rows to reveal under a row. */\n getChildren?: (row: T) => T[] | undefined;\n helper?: string;\n /** Trailing Info/drill-down column. Defaults to shown. */\n showInfoColumn?: boolean;\n /** Filter options pre-selected on mount, keyed by filter label. */\n defaultFilters?: Record<string, string[]>;\n /** When true, results appear only once the user types a query -- active\n * filters alone don't reveal the table (used where a filter is pre-selected). */\n requireQuery?: boolean;\n /** When true, the full catalog shows immediately without a search -- for\n * short, browsable lists (e.g. US states). */\n showResultsWithoutSearch?: boolean;\n /** When provided, a \"Search / Account lists\" source toggle appears and the\n * Account lists tab lets the user pull in whole uploaded lists. */\n accountLists?: SelectionPickerAccountList[];\n selectedListIds?: string[];\n onToggleList?: (id: string) => void;\n /** Rows that are already committed elsewhere and can't be toggled here --\n * they render dimmed with no checkbox at all (an \"Add\" picker shouldn't\n * offer to un-add something it isn't responsible for). Select-all skips\n * them, so it can't strip them out from under the caller. */\n lockedIds?: ReadonlySet<string>;\n /**\n * Externally-computed, already-filtered rows -- for a caller whose search\n * is server-side/async (loading, pagination) instead of a full in-memory\n * `catalog` filtered client-side. When given, this replaces `catalog`'s\n * own search/filter matching entirely: the component renders exactly\n * these rows, still gated by the same \"has the user searched or filtered\n * yet\" reveal rule as catalog mode. Pair with `onQueryChange` so the\n * caller knows what to search for, and with\n * `loading`/`error`/`hasMore`/`onLoadMore` for the rest of a typical async\n * search's states. Omit (the default) to keep the original catalog +\n * client-side search/filter behavior -- an existing caller's behavior\n * never changes just by picking up a new version of this component.\n */\n results?: T[];\n /** Fires on every keystroke in the search box with the new query text --\n * for a caller in `results` mode that needs to know what to search for.\n * Fire-and-forget; this component still owns the input's value either way. */\n onQueryChange?: (query: string) => void;\n /** Shows a centered spinner in place of rows. Only meaningful in `results` mode. */\n loading?: boolean;\n /** Shows a \"couldn't load\" message (see `errorMessage`) in place of rows. */\n error?: boolean;\n /** @default \"Couldn't load options. Please try again.\" */\n errorMessage?: string;\n /** Shows a \"Load more\" button below the results when another page is available. */\n hasMore?: boolean;\n /** Disables the Load more button and shows a small spinner in it while a page is already in flight. */\n loadingMore?: boolean;\n onLoadMore?: () => void;\n /** Extra toolbar content rendered after the built-in filter dropdowns --\n * e.g. a source/level multi-select the caller owns. A plain composition\n * slot; this component has no opinion on what it renders. */\n toolbarExtra?: ReactNode;\n /**\n * Optional prefix for `data-testid` attributes on the search input\n * (`${testIdPrefix}-search`), the source toggle buttons\n * (`${testIdPrefix}-source-search` / `-lists`), each filter dropdown\n * trigger (`${testIdPrefix}-filter-<slug>`) and its options, the\n * select-all checkbox (`${testIdPrefix}-select-all`), each row\n * (`${testIdPrefix}-row-<slug>`), the Load more button\n * (`${testIdPrefix}-load-more`), and each Account lists row/count\n * (`${testIdPrefix}-list-<id>` / `${testIdPrefix}-list-count`). Omit for\n * no test-id wiring.\n */\n testIdPrefix?: string;\n}\n\n/**\n * @pattern SelectionPicker\n * @description Generic search-and-filter picker for building a selection out\n * of a larger catalog -- a search box plus filter dropdowns above a checkbox\n * table, with an optional \"Search / Account lists\" source toggle for pulling\n * in whole pre-built lists at once. The table stays empty until the user\n * actually searches or filters (no pre-loaded catalog dump), and checking a\n * row commits immediately rather than staging into a separate \"Add\n * selected\" step. Supports two data modes: a full in-memory `catalog`\n * filtered client-side (the default), or externally-computed `results` for a\n * caller whose search is server-side/async, with `loading`/`error`/\n * `hasMore`/`onLoadMore` covering that mode's states.\n * @tokens rounded-control, rounded-card, border-border-default, bg-input,\n * bg-canvas, bg-surface, shadow-raised, shadow-overlay, text-text-primary,\n * text-text-secondary, text-text-tertiary, text-text-link,\n * text-brand-primaryAction, border-brand-primaryAction, bg-brand-primaryAction,\n * bg-brand-primarySoft, bg-subtle, rounded-full, hover:bg-subtle,\n * hover:bg-canvas, hover:text-text-primary, placeholder:text-text-tertiary,\n * cursor-default\n * @dependencies lucide-react, this package's own CheckBox\n * @behavior \"Select all\" is scoped to the current search/filter results (or\n * the currently-loaded page(s) of `results`), not the whole catalog, and\n * skips lockedIds throughout so it can't toggle rows it isn't responsible\n * for. Filter dropdowns are portal-rendered and close on outside-click,\n * Escape, or scroll. Long option lists (>8) get an in-dropdown search box.\n * Row and select-all checkboxes use this package's own `CheckBox`, wired\n * with both an `onChange` and the row's own `onClick` -- `CheckBox` stops\n * click propagation before firing `onChange`, which is exactly what lets it\n * sit inside a row that toggles on its own click without double-firing.\n * @a11y Search is an <input>; result rows and the account-list menu\n * (role=\"menu\") are buttons. Escape closes the menu. Loading, empty and\n * error states announce through role=\"status\", so a consumer should NOT\n * wrap this in its own live region -- that would double-announce.\n * @usage\n * ```tsx\n * <SelectionPicker\n * catalog={advertisers}\n * selected={selected}\n * onChange={setSelected}\n * columns={[{ key: 'name', header: 'Advertiser', render: (r) => r.name }]}\n * filters={[{ label: 'Category', options: categories, value: (r) => r.category }]}\n * />\n * <SelectionPicker\n * catalog={[]}\n * results={searchResults}\n * onQueryChange={setQuery}\n * loading={status === 'loading'}\n * error={status === 'error'}\n * hasMore={hasMore}\n * loadingMore={loadingMore}\n * onLoadMore={loadMore}\n * selected={selected}\n * onChange={setSelected}\n * columns={columns}\n * filters={[]}\n * toolbarExtra={<LevelMultiSelect checked={levels} onToggle={toggleLevel} options={levelOptions} />}\n * />\n * ```\n */\nexport function SelectionPicker<T extends PickerRow>({\n catalog = [],\n selected,\n onChange,\n columns,\n filters,\n searchPlaceholder = \"Search…\",\n getChildren,\n helper,\n showInfoColumn = true,\n defaultFilters,\n requireQuery = false,\n showResultsWithoutSearch = false,\n accountLists,\n selectedListIds,\n onToggleList,\n lockedIds,\n results,\n onQueryChange,\n loading = false,\n error = false,\n errorMessage = \"Couldn't load options. Please try again.\",\n hasMore = false,\n loadingMore = false,\n onLoadMore,\n toolbarExtra,\n testIdPrefix,\n}: SelectionPickerProps<T>) {\n const hasAccountLists = !!accountLists;\n const [source, setSource] = useState<\"search\" | \"lists\">(\"search\");\n const [query, setQuery] = useState(\"\");\n const [activeFilters, setActiveFilters] = useState<Record<string, Set<string>>>(() => {\n const init: Record<string, Set<string>> = {};\n if (defaultFilters) for (const [label, opts] of Object.entries(defaultFilters)) init[label] = new Set(opts);\n return init;\n });\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n\n const selectedIds = useMemo(() => new Set(selected.map((s) => s.id)), [selected]);\n\n const toggleFilter = (label: string, opt: string) => {\n setActiveFilters((prev) => {\n const next = { ...prev };\n const set = new Set(next[label] ?? []);\n set.has(opt) ? set.delete(opt) : set.add(opt);\n next[label] = set;\n return next;\n });\n };\n\n const activeFilterCount = filters.reduce((n, f) => n + (activeFilters[f.label]?.size ?? 0), 0);\n // The table stays empty until the user actually searches or filters -- no\n // pre-loaded catalog dump on first render.\n const hasSearched = showResultsWithoutSearch || query.trim().length > 0 || (!requireQuery && activeFilterCount > 0);\n\n const filteredCatalog = useMemo(() => {\n if (!hasSearched || results !== undefined) return [];\n const q = query.trim().toLowerCase();\n return catalog.filter((row) => {\n if (q && !row.name.toLowerCase().includes(q)) return false;\n for (const f of filters) {\n const active = activeFilters[f.label];\n if (active && active.size > 0) {\n const v = f.value(row);\n if (!v || !active.has(v)) return false;\n }\n }\n return true;\n });\n }, [hasSearched, results, catalog, query, filters, activeFilters]);\n\n // Externally-supplied rows (async/server search) take over entirely when\n // given; otherwise fall back to the catalog filtered above.\n const rows = results !== undefined ? results : filteredCatalog;\n\n const addRows = (add: T[]) => {\n const toAdd = add.filter((r) => !selectedIds.has(r.id));\n if (toAdd.length) onChange([...selected, ...toAdd]);\n };\n\n /** Checking a row adds it immediately; unchecking removes it immediately\n * (no separate \"Add selected\" staging step). */\n const toggleRow = (row: T) => {\n if (selectedIds.has(row.id)) {\n onChange(selected.filter((s) => s.id !== row.id));\n } else {\n addRows([row]);\n }\n };\n\n /** Scoped to the current search/filter results, not the whole catalog --\n * \"select all\" selects everything in view, not everything that exists.\n * Locked rows are excluded throughout: they can't be toggled individually,\n * so select-all must not toggle them either. */\n const toggleable = lockedIds ? rows.filter((r) => !lockedIds.has(r.id)) : rows;\n const allSelected = toggleable.length > 0 && toggleable.every((r) => selectedIds.has(r.id));\n const someSelected = toggleable.some((r) => selectedIds.has(r.id));\n\n const toggleAll = () => {\n if (allSelected) {\n const rowIds = new Set(toggleable.map((r) => r.id));\n onChange(selected.filter((s) => !rowIds.has(s.id)));\n } else {\n addRows(toggleable);\n }\n };\n\n const rowGridCols = showInfoColumn ? \"grid-cols-[36px_1fr_44px]\" : \"grid-cols-[36px_1fr]\";\n\n return (\n <div className=\"flex flex-col gap-4\">\n {helper && (\n <>\n <p className=\"text-[13px] text-text-secondary\">{helper}</p>\n <hr className=\"-mx-5 -mt-2 border-border-default sm:-mx-6\" />\n </>\n )}\n\n {/* Source toggle -- Search (browse + cherry-pick) vs Account lists\n (apply a whole uploaded list). Only shown when account lists are\n available for this picker. */}\n {hasAccountLists && (\n <div className=\"inline-flex gap-0.5 self-start rounded-control border border-border-default bg-canvas p-0.5\">\n {(\n [\n { id: \"search\", label: \"Search\", icon: Search },\n { id: \"lists\", label: \"Account lists\", icon: List },\n ] as const\n ).map((t) => {\n const on = source === t.id;\n return (\n <button\n key={t.id}\n type=\"button\"\n onClick={() => setSource(t.id)}\n data-testid={testIdPrefix && `${testIdPrefix}-source-${t.id}`}\n className={cx(\n \"inline-flex items-center gap-1.5 rounded-[6px] px-3 py-1.5 text-[13px] font-medium transition-colors\",\n on ? \"bg-surface text-text-primary shadow-raised\" : \"text-text-secondary hover:text-text-primary\"\n )}\n >\n <t.icon size={14} aria-hidden=\"true\" />\n {t.label}\n </button>\n );\n })}\n </div>\n )}\n\n {/* Results -- no card wrapper; the toolbar and table sit directly on\n the section's own background. */}\n {source === \"search\" && (\n <div className=\"flex min-w-0 flex-col gap-3\">\n {/* Toolbar -- search and filter dropdowns directly above the table.\n Checking a row adds it immediately, so there's no separate\n add-selected step here. */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"flex h-9 min-w-[200px] flex-1 items-center gap-2 rounded-control border border-border-default bg-input px-3\">\n <Search size={15} className=\"text-text-secondary\" aria-hidden=\"true\" />\n <input\n value={query}\n onChange={(e) => {\n const next = e.target.value;\n setQuery(next);\n onQueryChange?.(next);\n }}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n data-testid={testIdPrefix && `${testIdPrefix}-search`}\n className=\"h-full flex-1 bg-transparent text-sm outline-hidden placeholder:text-text-tertiary\"\n />\n </div>\n {filters.map((f) => (\n <FilterDropdown\n key={f.label}\n filter={f}\n active={activeFilters[f.label] ?? new Set()}\n onToggle={(opt) => toggleFilter(f.label, opt)}\n testIdPrefix={testIdPrefix}\n />\n ))}\n {toolbarExtra}\n </div>\n\n {!hasSearched ? (\n <div className=\"flex flex-col items-center gap-3 rounded-card border border-dashed border-border-default py-10 text-center\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-subtle\">\n <Search size={20} className=\"text-text-tertiary\" aria-hidden=\"true\" />\n </div>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-[14px] font-semibold text-text-primary\">Search to get started</p>\n <p className=\"text-[13px] text-text-tertiary\">Use the search or filters above to find and add options.</p>\n </div>\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-control border border-border-default\">\n <div\n className={cx(\n \"grid items-center gap-2 border-b border-border-default bg-canvas px-3 py-2 text-[11px] font-semibold uppercase tracking-[0.06em] text-text-secondary\",\n rowGridCols\n )}\n >\n <CheckBox\n checked={allSelected}\n indeterminate={!allSelected && someSelected}\n disabled={toggleable.length === 0}\n onChange={toggleAll}\n ariaLabel=\"Select all\"\n testId={testIdPrefix && `${testIdPrefix}-select-all`}\n />\n <div className={cx(\"grid gap-2\", gridForColumns(columns))}>\n {columns.map((c) => (\n <span key={c.key} className={c.className}>\n {c.header}\n </span>\n ))}\n </div>\n {showInfoColumn && <span className=\"text-right\">Info</span>}\n </div>\n\n <div className=\"max-h-[360px] overflow-y-auto\">\n {loading ? (\n <div className=\"flex items-center justify-center py-6\" role=\"status\" aria-label=\"Loading\">\n <Loader2 size={18} className=\"animate-spin text-text-tertiary\" aria-hidden=\"true\" />\n </div>\n ) : error ? (\n <p className=\"px-3 py-8 text-center text-[13px] text-text-tertiary\">{errorMessage}</p>\n ) : rows.length === 0 ? (\n <div className=\"px-3 py-8 text-center text-[13px] text-text-tertiary\">\n No matches. Try a different search or filter.\n </div>\n ) : (\n rows.map((row) => {\n const isSel = selectedIds.has(row.id);\n const isLocked = lockedIds?.has(row.id) ?? false;\n const kids = getChildren?.(row) as T[] | undefined;\n const isOpen = expanded.has(row.id);\n return (\n <div key={row.id} className=\"border-t border-border-default/60 first:border-t-0\">\n <div\n onClick={isLocked ? undefined : () => toggleRow(row)}\n aria-disabled={isLocked || undefined}\n className={cx(\n \"grid items-center gap-2 px-3 py-2.5\",\n rowGridCols,\n isLocked ? \"cursor-default opacity-50\" : \"cursor-pointer hover:bg-subtle\",\n !isLocked && isSel && \"opacity-60\"\n )}\n >\n {/* Locked rows keep the checkbox column as an empty\n spacer so every row's columns stay on the same grid. */}\n {isLocked ? (\n <span aria-hidden=\"true\" />\n ) : (\n <CheckBox\n checked={isSel}\n onChange={() => toggleRow(row)}\n ariaLabel={row.name}\n testId={testIdPrefix && `${testIdPrefix}-row-${slug(row.id)}`}\n />\n )}\n <div className={cx(\"grid gap-2 text-[13px] text-text-primary\", gridForColumns(columns))}>\n {columns.map((c) => (\n <span key={c.key} className={cx(\"truncate\", c.className)}>\n {c.render(row)}\n </span>\n ))}\n </div>\n {showInfoColumn && (\n <div className=\"flex items-center justify-end\">\n {kids && kids.length > 0 ? (\n <button\n type=\"button\"\n aria-label=\"Show details\"\n onClick={(e) => {\n e.stopPropagation();\n setExpanded((p) => {\n const n = new Set(p);\n n.has(row.id) ? n.delete(row.id) : n.add(row.id);\n return n;\n });\n }}\n className=\"flex h-7 w-7 items-center justify-center rounded-control text-text-secondary hover:bg-canvas hover:text-text-primary\"\n >\n <ChevronRight size={15} className={cx(\"transition-transform\", isOpen && \"rotate-90\")} />\n </button>\n ) : (\n <span\n className=\"flex h-7 w-7 items-center justify-center text-text-tertiary\"\n title=\"No additional details\"\n >\n <Info size={14} />\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Mock drill-down children */}\n {isOpen && kids && (\n <div className=\"bg-canvas/60 pb-1.5 pl-10 pr-3\">\n {kids.map((kid) => {\n const kidSel = selectedIds.has(kid.id);\n return (\n <div\n key={kid.id}\n className=\"flex items-center justify-between gap-2 border-t border-border-default/40 py-2 first:border-t-0\"\n >\n <span className=\"truncate text-[13px] text-text-secondary\">{kid.name}</span>\n <button\n type=\"button\"\n disabled={kidSel}\n onClick={() => addRows([kid])}\n className={cx(\n \"inline-flex items-center gap-1 rounded-control px-2 py-1 text-[12px] font-medium\",\n kidSel ? \"text-text-tertiary\" : \"text-text-link hover:bg-subtle\"\n )}\n >\n {kidSel ? <Check size={13} /> : <Plus size={13} />}\n {kidSel ? \"Added\" : \"Add\"}\n </button>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n })\n )}\n </div>\n\n {!loading && !error && hasMore && (\n <button\n type=\"button\"\n onClick={onLoadMore}\n disabled={loadingMore}\n data-testid={testIdPrefix && `${testIdPrefix}-load-more`}\n className=\"flex w-full items-center justify-center gap-2 border-t border-border-default px-2 py-1.5 text-[13px] text-brand-primaryAction transition-colors hover:bg-subtle disabled:opacity-50\"\n >\n {loadingMore ? <Loader2 size={13} className=\"animate-spin\" aria-hidden=\"true\" /> : null}\n {loadingMore ? \"Loading…\" : \"Load more\"}\n </button>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Account lists -- select whole uploaded lists as advertiser sources. */}\n {source === \"lists\" && (\n <div className=\"flex min-w-0 flex-col gap-3\">\n <p className=\"text-[13px] text-text-secondary\">\n Select an account list to add all of its accounts at once. Your workspace stays in sync as the list is updated.\n </p>\n {accountLists && accountLists.length > 0 ? (\n <>\n {/* Scrolls internally so a long catalog can't push the card's\n footer off-screen. The cap is deliberately set mid-row (5 rows\n + gaps = 365px, + ~half of row 6) rather than on a row\n boundary: a partially visible row is the affordance. The faded\n edge keeps that half-row from reading as a clipping bug. */}\n <ScrollFade className=\"flex max-h-[396px] flex-col gap-2 overflow-y-auto pr-0.5\">\n {accountLists.map((list) => {\n const on = (selectedListIds ?? []).includes(list.id);\n return (\n <button\n key={list.id}\n type=\"button\"\n onClick={() => onToggleList?.(list.id)}\n aria-pressed={on}\n data-testid={testIdPrefix && `${testIdPrefix}-list-${list.id}`}\n className={cx(\n \"flex items-center gap-3 rounded-control border px-3.5 py-3 text-left transition-colors\",\n on ? \"border-brand-primaryAction bg-brand-primarySoft\" : \"border-border-default bg-surface hover:bg-subtle\"\n )}\n >\n <span\n className={cx(\n \"flex h-5 w-5 shrink-0 items-center justify-center rounded-full\",\n on ? \"text-brand-primaryAction\" : \"text-text-secondary\"\n )}\n >\n {on ? <Check size={16} /> : <Plus size={16} />}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex min-w-0 items-center gap-2\">\n <span className=\"truncate text-[14px] font-medium text-text-primary\">{list.name}</span>\n </span>\n <span className=\"block truncate text-[12px] text-text-secondary\">\n {list.count} accounts · {list.entityTypes.join(\", \")} · Updated {formatListDate(list.updatedAt)}\n </span>\n </span>\n <span className={cx(\"shrink-0 text-[12px] font-medium\", on ? \"text-brand-primaryAction\" : \"text-text-secondary\")}>\n {on ? \"Added\" : \"Add\"}\n </span>\n </button>\n );\n })}\n </ScrollFade>\n {/* Closes off the scroll area, and the total tells the user there\n was more than the ~5 rows on screen -- the faded edge says they\n can scroll, this says why. */}\n <p\n className=\"border-t border-border-default pt-2 text-right text-[12px] font-medium text-text-tertiary\"\n data-testid={testIdPrefix && `${testIdPrefix}-list-count`}\n >\n {accountLists.length} {accountLists.length === 1 ? \"list\" : \"lists\"}\n </p>\n </>\n ) : (\n <div className=\"flex flex-col items-center gap-3 rounded-card border border-dashed border-border-default py-10 text-center\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-subtle\">\n <List size={20} className=\"text-text-tertiary\" aria-hidden=\"true\" />\n </div>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-[14px] font-semibold text-text-primary\">No account lists yet</p>\n <p className=\"text-[13px] text-text-tertiary\">Account lists set up for you will appear here.</p>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\n/** Height of the softened edge, in px. Matches ~2/3 of a list row so the fade\n * reads as \"continues\" without washing out the peeking row's label. */\nconst EDGE_FADE = 44;\n\n/**\n * A scroll container whose clipped edges fade out while content is hidden past\n * them -- the cue that the list keeps going. Pair it with a max-height that lands\n * mid-row: a partially visible row is the affordance, and the fade is what keeps\n * that half-row from reading as a clipping bug.\n *\n * The fade is a mask over the content rather than a colored scrim, so it needs\n * no knowledge of the surface behind it and works in both themes.\n */\nfunction ScrollFade({ className, children }: { className?: string; children: ReactNode }) {\n const elRef = useRef<HTMLDivElement | null>(null);\n const [edges, setEdges] = useState({ top: false, bottom: false });\n\n const sync = useCallback(() => {\n const el = elRef.current;\n if (!el) return;\n const top = el.scrollTop > 2;\n const bottom = el.scrollTop + el.clientHeight < el.scrollHeight - 2;\n // Bail when unchanged -- this runs on every scroll frame.\n setEdges((prev) => (prev.top === top && prev.bottom === bottom ? prev : { top, bottom }));\n }, []);\n\n // A callback ref (rather than an effect) so this runs the moment the node\n // mounts -- the container is conditionally rendered, so it can appear long\n // after the first render. We measure right here instead of relying on\n // ResizeObserver's initial callback, which is delivered on the frame pipeline\n // and so never arrives in a backgrounded tab. The observer then handles later\n // reflows (window resize, sidebar collapse).\n const attach = useCallback(\n (el: HTMLDivElement | null) => {\n elRef.current = el;\n if (!el) return;\n sync();\n const ro = new ResizeObserver(sync);\n ro.observe(el);\n return () => {\n ro.disconnect();\n elRef.current = null;\n };\n },\n [sync]\n );\n\n /** Opaque except at whichever edge is currently hiding content. */\n const mask =\n edges.top || edges.bottom\n ? `linear-gradient(to bottom, transparent 0, #000 ${edges.top ? EDGE_FADE : 0}px, #000 calc(100% - ${\n edges.bottom ? EDGE_FADE : 0\n }px), transparent 100%)`\n : undefined;\n\n return (\n <div ref={attach} onScroll={sync} className={className} style={{ maskImage: mask, WebkitMaskImage: mask }}>\n {children}\n </div>\n );\n}\n\nfunction formatListDate(iso: string) {\n try {\n return new Date(iso).toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n } catch {\n return iso;\n }\n}\n\n/** Toolbar filter -- a button that opens a checkbox popover, so multiple\n * filter dimensions fit on one line instead of a permanent sidebar. */\nfunction FilterDropdown<T extends PickerRow>({\n filter,\n active,\n onToggle,\n testIdPrefix,\n}: {\n filter: PickerFilter<T>;\n active: Set<string>;\n onToggle: (opt: string) => void;\n testIdPrefix?: string;\n}) {\n const [open, setOpen] = useState(false);\n const [q, setQ] = useState(\"\");\n const btnRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null);\n\n // Long option lists (e.g. the market list) get an in-dropdown search box.\n const searchable = filter.options.length > 8;\n const shownOptions =\n searchable && q.trim() ? filter.options.filter((o) => o.toLowerCase().includes(q.trim().toLowerCase())) : filter.options;\n\n // Positioned in a portal (not a plain `absolute` child) so it floats above\n // the picker's own scroll container instead of being clipped by it -- an\n // `overflow-y-auto` ancestor forces the x-axis to clip too, cutting off any\n // in-flow dropdown that extends past its right edge.\n useLayoutEffect(() => {\n if (!open || !btnRef.current) return;\n const r = btnRef.current.getBoundingClientRect();\n setPos({ top: r.bottom + 6, left: r.left });\n }, [open]);\n\n useEffect(() => {\n if (!open) {\n setQ(\"\");\n return;\n }\n const onDown = (e: MouseEvent) => {\n const t = e.target as Node;\n if (!btnRef.current?.contains(t) && !menuRef.current?.contains(t)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false);\n const onScroll = () => setOpen(false);\n window.addEventListener(\"mousedown\", onDown);\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"scroll\", onScroll, true);\n return () => {\n window.removeEventListener(\"mousedown\", onDown);\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"scroll\", onScroll, true);\n };\n }, [open]);\n\n const count = active.size;\n // Label reflects the selection: the filter's name when nothing is picked,\n // the single option's name when one is picked, or \"Multiple\" beyond that.\n const label = count === 0 ? filter.label : count === 1 ? [...active][0] : \"Multiple\";\n const filterSlug = slug(filter.label);\n\n return (\n <div className=\"relative\">\n <button\n ref={btnRef}\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-testid={testIdPrefix && `${testIdPrefix}-filter-${filterSlug}`}\n className=\"inline-flex h-9 items-center gap-1.5 whitespace-nowrap rounded-control border border-border-default bg-input px-3 text-[13px] font-medium text-text-secondary transition-colors hover:bg-subtle\"\n >\n {label}\n <ChevronDown size={13} aria-hidden=\"true\" className={cx(\"transition-transform\", open && \"rotate-180\")} />\n </button>\n\n {open &&\n pos &&\n createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n aria-label={filter.label}\n style={{ top: pos.top, left: pos.left }}\n className=\"fixed z-[80] min-w-[220px] rounded-card border border-border-default bg-surface p-2 shadow-overlay\"\n >\n {searchable && (\n <div className=\"mb-1.5 flex h-8 items-center gap-2 rounded-control border border-border-default bg-input px-2.5\">\n <Search size={14} className=\"shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <input\n autoFocus\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={`Search ${filter.label.toLowerCase()}…`}\n className=\"h-full flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary\"\n />\n </div>\n )}\n <div className={cx(\"flex flex-col gap-0.5\", searchable && \"max-h-[240px] overflow-y-auto\")}>\n {shownOptions.length === 0 ? (\n <p className=\"px-2 py-3 text-center text-[12px] text-text-secondary\">No matches.</p>\n ) : (\n shownOptions.map((opt) => {\n const on = active.has(opt);\n return (\n <label\n key={opt}\n className=\"flex cursor-pointer items-center gap-2 rounded-control px-2 py-1.5 text-[13px] text-text-primary hover:bg-subtle\"\n >\n <CheckBox\n checked={on}\n onChange={() => onToggle(opt)}\n ariaLabel={opt}\n testId={testIdPrefix && `${testIdPrefix}-filter-${filterSlug}-${slug(opt)}`}\n />\n {opt}\n </label>\n );\n })\n )}\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n\nfunction gridForColumns(columns: { className?: string }[]) {\n // Even columns by default; first column wider.\n if (columns.length <= 1) return \"grid-cols-1\";\n if (columns.length === 2) return \"grid-cols-[1.6fr_1fr]\";\n if (columns.length === 3) return \"grid-cols-[1.6fr_1fr_1fr]\";\n return \"grid-cols-[1.6fr_1fr_1fr_1fr]\";\n}\n","\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\n\nfunction cx(...parts: Array<string | false | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface PubBreak {\n brand: string;\n owner: string;\n tags: string[];\n spendN: number;\n pct: number;\n yoy: number | \"NEW\";\n}\n\nconst fmtM = (v: number) => (v >= 100 ? `$${Math.round(v)}M` : `$${v.toFixed(1)}M`);\n\n/** Prior-year spend derived from the current amount + YoY %, or null when\n * not computable (new this year, or a >=100% decline). */\nfunction priorYearAmt(spendN: number, yoy: number | \"NEW\"): string | null {\n if (yoy === \"NEW\" || yoy <= -100) return null;\n return fmtM(spendN / (1 + yoy / 100));\n}\n\n/** Initials-on-a-tile fallback used when no `renderLogo` is given -- no\n * image/CDN lookup, just the brand name's initials. */\nfunction initials(name: string): string {\n const words = name\n .replace(/[^a-zA-Z0-9 ]/g, \" \")\n .split(/\\s+/)\n .filter(Boolean);\n if (words.length >= 2) return (words[0][0] + words[1][0]).toUpperCase();\n return name.replace(/[^a-zA-Z0-9]/g, \"\").slice(0, 2).toUpperCase();\n}\n\nfunction Monogram({ name, size = 28 }: { name: string; size?: number }) {\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex shrink-0 items-center justify-center rounded-[6px] bg-subtle font-bold leading-none text-text-secondary\"\n style={{ width: size, height: size, fontSize: Math.round(size * 0.36) }}\n >\n {initials(name)}\n </span>\n );\n}\n\n/** Neutral descriptive chip for `tags` -- a local, minimal stand-in for this\n * package's own eventual shared Tag component; not cross-imported here\n * since Tag itself isn't part of this migration. */\nfunction BreakdownTag({ children }: { children: ReactNode }) {\n return (\n <span className=\"inline-flex items-center whitespace-nowrap rounded-full bg-subtle px-2 py-0.5 text-[11px] font-medium text-text-secondary\">\n {children}\n </span>\n );\n}\n\n/** Hover tooltip for the Previous/YoY column headers -- a simple\n * CSS-only, non-portalled bubble with a deliberate 1s hover delay (not\n * this package's own `InfoTip`, which is portalled/viewport-clamped and\n * opens immediately -- a different tradeoff for a different job: this one\n * never needs to escape a clipping ancestor, so it doesn't pay for a portal). */\nfunction DelayedTip({ label, children }: { label: string; children: ReactNode }) {\n return (\n <span className=\"group/dt relative inline-flex\" tabIndex={0} aria-label={label}>\n {children}\n <span\n role=\"tooltip\"\n className=\"pointer-events-none invisible absolute bottom-[calc(100%+6px)] left-1/2 z-40 w-[160px] -translate-x-1/2 rounded-control border border-border-default bg-surface px-2 py-1.5 text-center text-[11px] font-medium leading-snug text-text-secondary opacity-0 shadow-overlay transition-[opacity,visibility] delay-1000 duration-150 group-hover/dt:visible group-hover/dt:opacity-100 group-focus/dt:visible group-focus/dt:opacity-100\"\n >\n {label}\n </span>\n </span>\n );\n}\n\n// Shared Current/Previous/YoY column layout -- same fixed widths, sizing, and\n// coloring throughout the list.\nconst COL_CURRENT = 76;\nconst COL_PREVIOUS = 76;\nconst COL_YOY = 44;\n\nfunction MetricListHeader({ className }: { className?: string }) {\n return (\n <div className={cx(\"flex items-baseline gap-2 pb-2\", className)}>\n <span className=\"flex-1\" />\n <span className=\"flex shrink-0 items-center gap-2 pr-1.5\">\n <span className=\"text-right text-[11px] font-medium text-text-tertiary\" style={{ width: COL_CURRENT }}>\n Current\n </span>\n <DelayedTip label=\"Spend during the same time period one year ago.\">\n <span className=\"text-right text-[11px] font-medium text-text-tertiary\" style={{ width: COL_PREVIOUS }}>\n Previous\n </span>\n </DelayedTip>\n <DelayedTip label=\"Percent change from this time period vs. the same time one year ago.\">\n <span className=\"text-right text-[11px] font-medium text-text-tertiary\" style={{ width: COL_YOY }}>\n YoY\n </span>\n </DelayedTip>\n </span>\n </div>\n );\n}\n\nfunction MetricCells({ spendN, yoy }: { spendN: number; yoy: number | \"NEW\" }) {\n const prior = priorYearAmt(spendN, yoy);\n const up = yoy !== \"NEW\" && yoy >= 0;\n return (\n <span className=\"flex shrink-0 items-center gap-2 pr-1.5\">\n <span className=\"text-right text-[12px] font-bold tabular-nums text-text-primary\" style={{ width: COL_CURRENT }}>\n {fmtM(spendN)}\n </span>\n <span className=\"text-right text-[12px] font-normal tabular-nums text-text-primary\" style={{ width: COL_PREVIOUS }}>\n {prior ?? \"—\"}\n </span>\n <span className=\"flex justify-end\" style={{ width: COL_YOY }}>\n {yoy === \"NEW\" ? (\n <span className=\"rounded-full bg-status-warning/15 px-1.5 text-[10px] font-semibold text-text-warning\">NEW</span>\n ) : (\n <span className={cx(\"text-right text-[12px] font-semibold tabular-nums\", up ? \"text-text-success\" : \"text-text-danger\")}>\n {up ? \"+\" : \"−\"}\n {Math.abs(yoy)}%\n </span>\n )}\n </span>\n </span>\n );\n}\n\nexport interface PublisherBreakdownListProps {\n rows: PubBreak[];\n /** @default 10 */\n defaultVisibleCount?: number;\n /** Set false when the container already supplies its own padding. @default true */\n padded?: boolean;\n /** When provided, the truncated-list footer becomes a plain link instead of\n * the inline \"see all\" expand/collapse behavior. */\n viewAllHref?: string;\n /**\n * Custom per-row logo/avatar rendering -- e.g. a real logo-fetching hook or\n * a brand-name-to-domain favicon lookup. Defaults to a plain initials\n * monogram so the component works with zero configuration; this package\n * intentionally doesn't ship a brand -> logo/domain lookup table, since\n * that's fixture/business data, not a design-system concern.\n */\n renderLogo?: (row: PubBreak) => ReactNode;\n}\n\n/**\n * @pattern PublisherBreakdownList\n * @description Flat Current/Previous/YoY spend list, prop-driven end to end\n * -- no data fetching of its own. Row padding is configurable so it can sit\n * flush inside a bordered card or inline within an already-padded container.\n * mr-clientapps-insights-studio's analogous \"Top publishers\" UI\n * (`PublisherBreakdown.tsx`) was evaluated for reconciliation and\n * deliberately NOT merged into this component -- see the escape-hatch note\n * below. `renderLogo` lets a caller plug in real per-row logos; without it,\n * rows show a plain initials monogram.\n * @tokens text-text-primary, text-text-tertiary, text-text-secondary,\n * text-text-link, text-text-warning, text-text-success, text-text-danger,\n * border-border-default, bg-surface, bg-subtle, rounded-control, rounded-full,\n * shadow-overlay\n * @behavior Truncates to `defaultVisibleCount` rows with a \"See all (N more)\"\n * / \"Show less\" toggle, unless `viewAllHref` is given, in which case the\n * footer becomes a plain link out instead (e.g. to a full breakdown page).\n *\n * Escape hatch: mr-clientapps-insights-studio's own publisher breakdown\n * (`domains/reviews/src/components/media-spend/PublisherBreakdown.tsx`) is a\n * genuinely different component, not just a differently-styled copy of this\n * one -- a three-level Owner/Publisher/Property accordion, each level\n * independently paginated against a live API (`usePublisherBreakdown`/\n * `usePublisherBreakdownChildren`), with per-row logo fetching via a batched\n * hook. None of that -- the recursive expand/collapse tree, the live\n * fetching, the level toggle -- has an equivalent in this flat,\n * fully-synchronous, prop-driven list, and bolting it on would mean either\n * building the accordion machinery into every consumer of this component\n * (including ones that only ever wanted a flat list, like the Opportunities\n * battle card) or branching internally on which \"mode\" is active -- exactly\n * the kind of forked-with-extra-indirection outcome this package's README\n * calls out as not actually shared. Per that guidance, this component stays\n * the flat-list case only; mr-clientapps' accordion stays where it is, un-migrated.\n * @a11y Rows are buttons. One row manages tabIndex directly and a row tooltip\n * uses role=\"tooltip\", dismissed on Escape. The tooltip describes rather\n * than names, so never put a row's only label in it.\n * @usage\n * ```tsx\n * <PublisherBreakdownList rows={publishers} defaultVisibleCount={10} />\n * ```\n */\nexport function PublisherBreakdownList({ rows, defaultVisibleCount = 10, padded = true, viewAllHref, renderLogo }: PublisherBreakdownListProps) {\n const [showAll, setShowAll] = useState(false);\n const visible = showAll ? rows : rows.slice(0, defaultVisibleCount);\n const rowPad = padded ? \"px-5\" : \"\";\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <MetricListHeader className={rowPad} />\n {visible.map((p) => (\n <div key={p.brand} className={cx(\"flex items-center justify-between gap-3 border-t border-border-default/60 py-2.5 first:border-t-0\", rowPad)}>\n <div className=\"flex min-w-0 items-center gap-2.5\">\n {renderLogo ? renderLogo(p) : <Monogram name={p.brand} size={28} />}\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <span className=\"text-[14px] font-semibold text-text-primary\">{p.brand}</span>\n {p.tags.map((t) => (\n <BreakdownTag key={t}>{t}</BreakdownTag>\n ))}\n </div>\n <div className=\"truncate text-[11.5px] text-text-tertiary\">{p.owner}</div>\n </div>\n </div>\n <MetricCells spendN={p.spendN} yoy={p.yoy} />\n </div>\n ))}\n </div>\n {rows.length > defaultVisibleCount &&\n (viewAllHref ? (\n <div className={cx(\"border-t border-border-default py-3\", rowPad)}>\n <a href={viewAllHref} className=\"text-[12px] font-semibold text-text-link hover:underline\">\n See all publishers\n </a>\n </div>\n ) : (\n <div className={cx(\"flex items-center gap-2 border-t border-border-default py-3 text-[12px] text-text-tertiary\", rowPad)}>\n <span>\n Showing {visible.length} of {rows.length}\n </span>\n {!showAll ? (\n <button type=\"button\" onClick={() => setShowAll(true)} className=\"font-semibold text-text-link hover:underline\">\n See all ({rows.length - defaultVisibleCount} more)\n </button>\n ) : (\n <button type=\"button\" onClick={() => setShowAll(false)} className=\"font-semibold text-text-link hover:underline\">\n Show less\n </button>\n )}\n </div>\n ))}\n </div>\n );\n}\n","import { type ButtonHTMLAttributes, type ReactNode, forwardRef } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Loader2 } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\n// text-brand-onprimary / text-status-onstatus are lowercase on purpose: that's\n// how @mediaradar/design-tokens' theme.css names them. insights-studio-prototype's\n// camelCase onPrimary/onStatus classes only worked through its own local\n// aliases (same values), which other apps don't have.\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-control transition-all duration-(--mr-motion-duration-interactive) ease-interactive disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-hidden focus-visible:ring-0\",\n {\n variants: {\n variant: {\n primary: \"bg-brand-primaryAction text-brand-onprimary hover:brightness-110\",\n // border-strong, not border-interactive. The interactive token is #6b6358\n // -- 5.9:1 against the surface, nearly as dark as body text -- which is\n // right for an input the eye must find in a form, and far too heavy for\n // a button sitting beside other buttons. It reads heaviest on icon-only,\n // where there is least fill inside the line to balance it.\n secondary: \"bg-surface text-text-primary border border-border-strong hover:bg-subtle hover:border-border-interactive\",\n ghost: \"text-text-primary hover:bg-subtle\",\n danger: \"bg-status-danger text-status-onstatus hover:brightness-110\",\n // Quiet destructive: neutral at rest, red only on hover. This is what\n // the product actually reaches for -- nearly every hand-rolled\n // destructive control is an icon that reddens on hover, while filled\n // `danger` is right only for the confirm button in a dialog the user\n // already opened.\n dangerGhost: \"text-text-secondary hover:bg-subtle hover:text-text-danger\",\n link: \"text-text-link underline-offset-4 hover:underline px-0\",\n },\n // Type scales with the box. One size across all three left xs cramped --\n // 14px inside a 24px box leaves five pixels above and below, so the label\n // fills the button instead of sitting in it.\n size: {\n xs: \"h-6 px-2 text-xs\",\n sm: \"h-8 px-3 text-sm\",\n md: \"h-10 px-4 text-sm\",\n },\n // Shape is orthogonal to size. As a fourth SIZE, `icon` could only ever\n // be one dimension, so an icon button never lined up with the labelled\n // buttons beside it in a toolbar. As a shape it squares the box at\n // whichever height you picked.\n iconOnly: {\n true: \"p-0\",\n false: \"\",\n },\n },\n compoundVariants: [\n { size: \"xs\", iconOnly: true, class: \"w-6\" },\n { size: \"sm\", iconOnly: true, class: \"w-8\" },\n { size: \"md\", iconOnly: true, class: \"w-10\" },\n // A boxed button is a target you aim at, so its label carries the weight\n // of one. `link` sits inline in a sentence, where semibold reads as\n // emphasis on the words rather than as a control.\n { variant: [\"primary\", \"secondary\", \"ghost\", \"danger\", \"dangerGhost\"], class: \"font-semibold\" },\n { variant: \"link\", class: \"font-medium h-auto p-0\" },\n ],\n defaultVariants: {\n variant: \"primary\",\n size: \"md\",\n iconOnly: false,\n },\n }\n);\n\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n /**\n * Render the button styling onto the single child element instead of a\n * `<button>` (e.g. a router `<Link>` or an `<a>`). The child must be exactly\n * one React element; it keeps its own tag, content and semantics.\n */\n asChild?: boolean;\n /**\n * Shows a spinner in place of the leading edge and disables the button.\n * With `asChild` there is no spinner (the child owns its content, and a\n * spinner belongs inside a real `<button>`): `loading` only sets\n * `aria-busy` and forwards `disabled` to the child, which only has an\n * effect on elements that support it -- an `<a>` stays clickable, so block\n * navigation yourself while loading.\n */\n loading?: boolean;\n /** Button label and/or icon. With `asChild`, the single element that receives the button styling. */\n children?: ReactNode;\n}\n\n/**\n * @pattern Button\n * @description The one control for every clickable action, from the main call\n * to action on a screen down to a quiet toolbar utility. Six variants\n * (primary, secondary, ghost, danger, dangerGhost, link) across three sizes\n * (xs, sm, md), labelled or icon-only.\n * Supports polymorphic rendering via `asChild` (Radix Slot) to apply button\n * styling to a different element, e.g. a router `<Link>`. Also exports the\n * raw `buttonVariants` cva function for consumers composing button styling\n * onto something other than this component.\n * @tokens bg-brand-primaryAction, text-brand-onprimary, bg-surface, text-text-primary, border-border-strong, hover:border-border-interactive, hover:bg-subtle, bg-status-danger, text-status-onstatus, text-text-secondary, hover:text-text-danger, text-text-link, rounded-control, duration-(--mr-motion-duration-interactive), ease-interactive\n * @dependencies class-variance-authority, @radix-ui/react-slot, lucide-react\n * @variant primary - The one primary action on a screen. Solid brand fill.\n * @variant secondary - Any other real action competing for attention (Cancel, Export). Bordered, neutral fill.\n * @variant ghost - Low-emphasis action inside a dense toolbar or row where a border would add visual noise.\n * @variant danger - Filled red. Only for a confirmed destructive action, typically the confirm button in a dialog. Never pair with `primary` in the same control group.\n * @variant dangerGhost - Neutral at rest, red on hover. For a destructive affordance inline in a row or toolbar -- what the product reaches for far more often than filled danger.\n * @variant link - Reads as inline text, not a control. Use inside body copy or where a full button would overpower the surrounding content.\n * @behavior `disabled` removes pointer events entirely (not just a style\n * change) and dims to 40% opacity. Focus handling is a deliberate exception:\n * most interactive components use a visible `focus-visible:outline-2` ring,\n * but Button suppresses it (`focus-visible:outline-hidden focus-visible:ring-0`)\n * and relies on its per-variant hover/brightness treatment instead. `loading`\n * implies `disabled` (and sets `aria-busy`), since a control mid-submit\n * shouldn't accept another click. `asChild` renders only the child element,\n * through Radix `Slot`, with the button classes, ref and remaining props\n * merged onto it -- no wrapping `<button>`. With `asChild`, `loading` draws\n * no spinner; it sets `aria-busy` and forwards `disabled`, which an `<a>`\n * ignores, so a loading link stays clickable unless the caller blocks it.\n * @a11y Renders a native <button>, so it keeps native keyboard behaviour\n * (with `asChild`, the child element's own semantics apply instead).\n * `loading` sets aria-busy, and the spinner is aria-hidden. Icon-only\n * usage needs an aria-label from the caller -- nothing here supplies one.\n * @use when the user is triggering an action in place -- saving, applying,\n * confirming, opening a dialog, running an export.\n * @use when you need a destructive affordance: dangerGhost inline in a row or\n * toolbar, danger only as the confirm button in a dialog already opened.\n * @use when an action sits inside a sentence -- variant=\"link\", which drops\n * the box and the semibold weight so it does not read as emphasis.\n * @use when the action is icon-only in a dense toolbar -- iconOnly squares the\n * box at whichever size you picked, so it lines up with labelled buttons\n * beside it. Supply an aria-label; nothing here does.\n * @avoid when the control navigates to a different route -- render a real link\n * via asChild, so middle-click, right-click and open-in-new-tab keep working.\n * variant=\"link\" styles a button as text; it does not make a button a link.\n * @avoid when there is already a primary on the screen -- a second primary\n * means neither reads as the main action. Use secondary or ghost.\n * @avoid when the control toggles a persistent on/off state -- use CheckBox or\n * a switch. A button fires; it does not hold a state.\n * @avoid when you are about to hand-roll a button with raw classes. There is\n * no case this does not cover, and every copy is a divergence in hover, focus,\n * disabled and loading behaviour at once.\n * @usage\n * ```tsx\n * <Button variant=\"primary\" size=\"md\">Save changes</Button>\n * <Button variant=\"dangerGhost\" size=\"sm\" iconOnly aria-label=\"Remove row\"><X size={15} /></Button>\n * <Button variant=\"secondary\" size=\"sm\">Cancel</Button>\n * <Button variant=\"danger\">Delete</Button>\n * <Button variant=\"primary\" loading>Saving…</Button>\n * <Button asChild variant=\"secondary\"><a href=\"/reports\">View reports</a></Button>\n * ```\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, iconOnly, asChild = false, loading = false, disabled, children, ...props }, ref) => {\n const shared = {\n className: cn(buttonVariants({ variant, size, iconOnly, className })),\n disabled: disabled || loading,\n \"aria-busy\": loading || undefined,\n ...props,\n };\n // Slot needs exactly one child element. The spinner can't sit beside it:\n // React counts even a `false` from `{loading && ...}` as a child, which is\n // what made every `asChild` render throw before 0.12.0.\n if (asChild) {\n return (\n <Slot ref={ref} {...shared}>\n {children}\n </Slot>\n );\n }\n return (\n <button ref={ref} {...shared}>\n {loading && <Loader2 className=\"size-4 shrink-0 animate-spin\" aria-hidden=\"true\" />}\n {children}\n </button>\n );\n }\n);\nButton.displayName = \"Button\";\n\nexport { buttonVariants };\n","import { Button } from \"./Button\";\nimport { cn } from \"./cn\";\n\nexport interface FilterDropdownFooterProps {\n /** Omit to hide the Clear All action for dropdowns that don't need it. */\n onClear?: () => void;\n /** Fires when the primary action is pressed. */\n onApply: () => void;\n clearLabel?: string;\n applyLabel?: string;\n}\n\n/**\n * @pattern FilterDropdownFooter\n * @description Fixed Apply/Clear All footer for quick-filter dropdowns —\n * pinned below the (independently scrollable) option list so it's always\n * visible. Shared by the Media/Advertiser/Date/Group By/Time Increment quick\n * filters on Sports Dashboard, Publisher Intel, and Opportunities.\n * @tokens border-border-default\n * @a11y Clear and Apply are real Buttons with visible text as their accessible\n * names, in that DOM order. It adds no roles or live regions of its own --\n * the menu that contains it owns dismissal and focus.\n * @usage\n * ```tsx\n * <FilterDropdownFooter onApply={handleApply} onClear={handleClear} />\n * ```\n */\nexport function FilterDropdownFooter({\n onClear,\n onApply,\n clearLabel = \"Clear all\",\n applyLabel = \"Apply\",\n}: FilterDropdownFooterProps) {\n return (\n <div\n className={cn(\n \"flex items-center gap-2 border-t border-border-default p-2\",\n onClear ? \"justify-between\" : \"justify-end\"\n )}\n >\n {onClear && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onClear}>\n {clearLabel}\n </Button>\n )}\n <Button type=\"button\" variant=\"primary\" size=\"sm\" onClick={onApply}>\n {applyLabel}\n </Button>\n </div>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"./Button\";\nimport { CheckBox } from \"./CheckBox\";\n\nexport interface NameListModalProps {\n title: string;\n initialName: string;\n submitLabel: string;\n onCancel: () => void;\n /**\n * Called with the trimmed name, and the state of `options` when any were\n * given. A handler that only takes the name stays valid -- TypeScript lets\n * a function ignore trailing parameters -- so existing callers are\n * unaffected.\n */\n onSubmit: (name: string, checked: Record<string, boolean>) => void;\n /**\n * Relabels the name field, for dialogs that name something other than a\n * list (e.g. \"View name\").\n */\n fieldLabel?: string;\n /** Placeholder for the name field, paired with `fieldLabel`. */\n placeholder?: string;\n /**\n * Optional checkboxes below the name field -- e.g. \"Set as default\" or\n * \"Enable email alerts\". Their state is handed to `onSubmit` as the second\n * argument, keyed by `key`. `initial` sets the starting state.\n */\n options?: { key: string; label: string; initial?: boolean }[];\n}\n\n/**\n * @pattern NameListModal\n * @description Create/rename dialog — a name field, and optionally a few\n * checkboxes under it. Shared by the Account Lists table and the list detail\n * page so create/rename look identical; `fieldLabel`/`placeholder` relabel it\n * for dialogs that name something other than a list.\n * @tokens bg-scrim, rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, rounded-control, bg-input, focus:border-brand-primaryAction\n * @behavior Escape closes the dialog via `onCancel`, same as clicking the\n * scrim backdrop. Submit is disabled until the name is non-empty (trimmed).\n * When `options` are given they render as CheckBox rows below the field, and\n * their state comes back as `onSubmit`'s second argument -- a handler that\n * only takes the name stays valid.\n * @a11y role=\"dialog\" with aria-modal, labelled by its title. The name field\n * takes focus on open and Escape closes via onCancel. Focus is NOT trapped\n * and NOT restored to the opener on close -- confirmed in the source -- so\n * a consumer that needs either must supply it around this component.\n * @usage\n * ```tsx\n * <NameListModal title=\"Rename list\" initialName={list.name} submitLabel=\"Save\" onCancel={close} onSubmit={rename} />\n * ```\n */\nexport function NameListModal({\n title,\n initialName,\n submitLabel,\n onCancel,\n onSubmit,\n fieldLabel = \"List name\",\n placeholder = \"e.g. Q4 prospecting targets\",\n options,\n}: NameListModalProps) {\n const [name, setName] = useState(initialName);\n const [checked, setChecked] = useState<Record<string, boolean>>(() =>\n Object.fromEntries((options ?? []).map((o) => [o.key, !!o.initial]))\n );\n const toggle = (key: string) => setChecked((c) => ({ ...c, [key]: !c[key] }));\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onCancel();\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [onCancel]);\n\n return createPortal(\n // bg-scrim, not a literal: design-tokens gained a scrim token in 2.5.0.\n // No in-data-[theme=dark] override needed any more -- the token redefines\n // itself under that attribute in dark.css, so one class covers both themes.\n <div\n className=\"fixed inset-0 z-70 flex items-center justify-center bg-scrim px-4\"\n onMouseDown={(e) => e.target === e.currentTarget && onCancel()}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n className=\"w-full max-w-[420px] rounded-card border border-border-default bg-surface p-5 shadow-overlay\"\n >\n <h2 className=\"text-[16px] font-semibold text-text-primary\">{title}</h2>\n <div className=\"mt-4 flex flex-col gap-1.5\">\n <label htmlFor=\"account-list-name\" className=\"text-[12px] font-medium text-text-secondary\">\n {fieldLabel}\n </label>\n <input\n id=\"account-list-name\"\n autoFocus\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={placeholder}\n className=\"h-10 rounded-control border border-border-default bg-input px-3 text-sm outline-hidden focus:border-brand-primaryAction\"\n />\n </div>\n {options && options.length > 0 && (\n <div className=\"mt-4 flex flex-col gap-2.5\">\n {options.map((o) => (\n <label key={o.key} className=\"flex cursor-pointer items-center gap-2.5 text-[13px] text-text-primary\">\n <CheckBox checked={!!checked[o.key]} onChange={() => toggle(o.key)} ariaLabel={o.label} />\n {o.label}\n </label>\n ))}\n </div>\n )}\n <div className=\"mt-5 flex items-center justify-end gap-2\">\n <Button variant=\"secondary\" onClick={onCancel}>\n Cancel\n </Button>\n <Button disabled={!name.trim()} onClick={() => onSubmit(name.trim(), checked)}>\n {submitLabel}\n </Button>\n </div>\n </div>\n </div>,\n document.body\n );\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"./cn\";\n\n/**\n * Which stroke a chip trigger carries.\n * - `box` : the boxed two-line chip (caption over value), on the default\n * border. The common filter-bar chip.\n * - `inline` : the same white fill with a darker stroke, for chips sitting\n * directly on the warm canvas with no boxed shell around them.\n */\nexport type ChipVariant = \"box\" | \"inline\";\n\n/** Shared styling for filter-bar chip triggers, so every dropdown chip matches. */\nexport function chipTriggerClass(variant: ChipVariant = \"box\") {\n return cn(\n \"flex h-11 items-center gap-2 rounded-control border bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus\",\n // Both variants sit on the input fill. `inline` carries the darker stroke\n // so it still reads as a control against the warm canvas with no boxed\n // shell behind it.\n variant === \"inline\" ? \"border-border-strong\" : \"border-border-default\"\n );\n}\n\nexport interface ChipContentProps {\n /** Small uppercase label above the value. */\n caption: string;\n /** The current selection, shown below the caption. */\n value: ReactNode;\n /** Optional leading icon rendered before the caption/value stack. */\n icon?: ReactNode;\n}\n\n/**\n * @pattern ChipTrigger\n * @description Shared foundation for filter-bar chip triggers — pairs\n * `chipTriggerClass` with `ChipContent` for the caption/value/icon layout, so\n * every dropdown chip across the app matches.\n * @tokens rounded-control, bg-input, border-border-default, border-border-strong, text-text-secondary, text-text-tertiary, text-text-primary, hover:bg-subtle, focus-visible:outline-border-focus, hover:text-text-primary\n * @behavior `chipTriggerClass` takes a `ChipVariant`: `box` (default, the\n * boxed two-line chip on the default border) or `inline` (same fill, darker\n * stroke, for chips sitting directly on the canvas). It is an argument to\n * that function, not a prop on `ChipContent`.\n * Provides only the shared `focus-visible:outline-2` keyboard-focus\n * treatment every dropdown trigger depends on — open/close, Escape, and\n * outside-click dismissal all live in each consumer, not here. A new dropdown\n * built on `chipTriggerClass` has to implement its own dismissal handling.\n * @a11y `chipTriggerClass` supplies only the shared focus-visible outline.\n * Roles, aria-expanded and dismissal all belong to the consumer's own\n * trigger -- this styles a control, it does not make one.\n * @usage\n * ```tsx\n * <button className={chipTriggerClass(\"box\")}>\n * <ChipContent caption=\"Media Type\" value=\"All\" />\n * </button>\n * ```\n */\nexport function ChipContent({ caption, value, icon }: ChipContentProps) {\n const stack = (\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] uppercase tracking-wide text-text-tertiary\">{caption}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n );\n if (icon) {\n return (\n <span className=\"flex items-center gap-2\">\n <span className=\"shrink-0 text-text-tertiary\">{icon}</span>\n {stack}\n </span>\n );\n }\n return stack;\n}\n","import { CircleSlash, X } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\ninterface ChipLike {\n key: string;\n label: string;\n groupLabel: string;\n}\n\nexport interface FilterChipBarProps<T extends ChipLike> {\n /** Any `{ key, label, groupLabel }` shape — only those fields are read. */\n chips: T[];\n onRemove: (chip: T) => void;\n onClearAll: () => void;\n /**\n * Chip keys that are kept but not applied (e.g. a filter the active\n * workspace can't resolve). Rendered inactive, still removable.\n */\n parkedKeys?: Set<string>;\n}\n\n/**\n * @pattern FilterChipBar\n * @description Applied-filter chips — wrap freely across as many rows as\n * needed, every chip shown. Each chip reveals its filter category on hover\n * (tooltip + outline). \"Clear all\" trails the chips. Generic over the\n * page's own chip type — only the shared key/label/groupLabel fields are\n * used.\n * @tokens rounded-full, bg-subtle, text-text-secondary, text-text-link, text-text-tertiary, bg-text-primary, border-border-default, group-hover:bg-border-default, group-hover:ring-border-interactive, group-hover:text-text-primary, group-hover:text-text-secondary, hover:text-text-primary, shadow-raised, text-surface\n * @dependencies lucide-react\n * @behavior A parked chip (key in `parkedKeys`) renders with no fill and a\n * dashed edge instead of the solid applied style, and its hover tooltip\n * reads \"Not in this workspace\" instead of the filter's group label.\n * @a11y Each chip's remove control is a button with its own aria-label naming\n * what it clears; the chip's icon is aria-hidden. An overflow tooltip uses\n * role=\"tooltip\", which describes rather than labels.\n * @usage\n * ```tsx\n * <FilterChipBar chips={activeChips} onRemove={removeChip} onClearAll={clearAll} />\n * ```\n */\nexport function FilterChipBar<T extends ChipLike>({ chips, onRemove, onClearAll, parkedKeys }: FilterChipBarProps<T>) {\n if (chips.length === 0) return null;\n\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 border-t border-border-default pt-2.5\">\n {chips.map((c) => (\n <Chip\n key={c.key}\n label={c.label}\n groupLabel={c.groupLabel}\n parked={!!parkedKeys?.has(c.key)}\n onRemove={() => onRemove(c)}\n />\n ))}\n <button type=\"button\" onClick={onClearAll} className=\"ml-1 text-[12px] font-medium text-text-link hover:underline\">\n Clear all\n </button>\n </div>\n );\n}\n\nfunction Chip({\n label,\n groupLabel,\n parked,\n onRemove,\n}: {\n label: string;\n groupLabel: string;\n parked: boolean;\n onRemove: () => void;\n}) {\n return (\n <span className=\"group relative inline-flex\">\n <span\n className={cn(\n \"flex items-center gap-1 rounded-full px-2.5 py-1 text-[12px] font-medium ring-1 transition-colors\",\n parked\n ? // No fill, dashed edge, muted label: reads as \"held, not acting on\n // anything\" against the solid applied chips beside it.\n \"border border-dashed border-border-default bg-transparent text-text-tertiary ring-transparent group-hover:text-text-secondary\"\n : \"bg-subtle text-text-secondary ring-transparent group-hover:bg-border-default group-hover:text-text-primary group-hover:ring-border-interactive\"\n )}\n >\n {parked && <CircleSlash size={11} aria-hidden=\"true\" className=\"shrink-0 text-text-tertiary\" />}\n {label}\n <button\n type=\"button\"\n onClick={onRemove}\n aria-label={`Remove ${groupLabel}: ${label}`}\n className=\"text-text-tertiary transition-colors hover:text-text-primary\"\n >\n <X size={12} />\n </button>\n </span>\n <span\n role=\"tooltip\"\n className=\"pointer-events-none absolute bottom-full left-1/2 z-20 mb-1.5 -translate-x-1/2 whitespace-nowrap rounded-md bg-text-primary px-2 py-1 text-[11px] font-medium text-surface opacity-0 shadow-raised transition-opacity duration-150 group-hover:opacity-100\"\n >\n {parked ? \"Not in this workspace\" : groupLabel}\n </span>\n </span>\n );\n}\n","import { ArrowUp, ArrowDown, ArrowUpDown } from \"lucide-react\";\nimport { cn } from \"./cn\";\nimport type { SortDir } from \"./tableSort\";\n\nexport interface SortButtonProps<K extends string> {\n label: string;\n sortKey: K;\n /** Current sort; a null `key` renders every SortButton inactive. See `sortProp`. */\n sort: { key: K | null; dir: SortDir };\n onSort: (key: K) => void;\n /** True when there are no rows to order — hides the arrow, drops the click. */\n disabled?: boolean;\n /**\n * False renders the label alone, as plain text with no button, for a column\n * that can never be sorted. Unlike `disabled`, nothing about it is a control.\n */\n sortable?: boolean;\n /** Matches the column's alignment, so a label that wraps lines up with the cells under it. */\n align?: \"left\" | \"center\" | \"right\";\n /** Optional prefix for the button's `data-testid` (`${testIdPrefix}-sort-${sortKey}`). Omit for no test-id wiring. */\n testIdPrefix?: string;\n}\n\nconst ALIGN = {\n left: \"justify-start text-left\",\n center: \"justify-center text-center\",\n right: \"justify-end text-right\",\n} as const;\n\n/**\n * @pattern SortButton\n * @description Design-system rule: every sortable table column header uses\n * this exact icon/color treatment. Sortable-but-inactive columns show a\n * neutral ArrowUpDown in text-tertiary at half opacity, coming up to full on\n * hover so the column reads as clickable; the active column swaps to a\n * direction arrow (ArrowUp/ArrowDown) colored with the brand action blue.\n * @tokens text-text-tertiary, text-brand-primaryAction, hover:text-text-primary\n * @dependencies lucide-react\n * @behavior Pair with `cycleSort`/`sortProp` (exported alongside) for the\n * standard three-state cycle — sort, reverse, then unsorted. `disabled` keeps\n * the column's inherited header color rather than dimming it — the column\n * isn't unavailable, there's just no data under it.\n * `sortable={false}` renders just the label, for a column that is never\n * sortable; `align` matches the column's alignment.\n * @a11y Renders a <button> inside the <th>. The sort state is announced from\n * the column header, not the button: aria-sort is only valid on a\n * columnheader, so the caller sets it on the <th> with `ariaSortFor` (exported\n * alongside). It gives the active column \"ascending\"/\"descending\" and leaves\n * every other header without the attribute.\n * @usage\n * ```tsx\n * const [sort, setSort] = useState<SortState<'spend'>>(null)\n * <th aria-sort={ariaSortFor(sort, 'spend')}>\n * <SortButton label=\"Spend\" sortKey=\"spend\" sort={sortProp(sort)} onSort={(k) => setSort(cycleSort(sort, k))} />\n * </th>\n * <th className=\"text-right\" aria-sort={ariaSortFor(sort, 'units')}>\n * <SortButton label=\"Units\" sortKey=\"units\" align=\"right\" sort={sortProp(sort)} onSort={onSort} />\n * </th>\n * ```\n */\nexport function SortButton<K extends string>({\n label,\n sortKey,\n sort,\n onSort,\n disabled = false,\n sortable = true,\n align = \"left\",\n testIdPrefix,\n}: SortButtonProps<K>) {\n if (!sortable) return <span className={cn(\"inline-flex\", ALIGN[align])}>{label}</span>;\n const active = !disabled && sort.key === sortKey;\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={() => onSort(sortKey)}\n data-testid={testIdPrefix && `${testIdPrefix}-sort-${sortKey}`}\n className={cn(\n // ALIGN's text-* overrides the UA default on <button>, which would centre a\n // label that wraps onto two lines, out of step with the column under it.\n // `uppercase` is NOT this control imposing a treatment -- it is\n // restoring one. Every table header row sets uppercase on the <tr>,\n // and a <button> does not inherit text-transform from its parent\n // (measured: the <th> computes `uppercase`, the button inside it\n // computes `none`), so without this a sortable label renders\n // sentence case beside caps neighbours in the same band.\n //\n // Letter-spacing DOES inherit, which is why no tracking is set here.\n // This control used to set its own `tracking-wide` while every\n // header row sets `tracking-wider`, so sortable labels rendered\n // subtly tighter than the fixed headers next to them. A control\n // should carry exactly the properties that do not inherit, and\n // nothing more.\n \"group inline-flex items-center gap-1 uppercase transition-colors\",\n ALIGN[align],\n !disabled && \"hover:text-text-primary\"\n )}\n >\n {label}\n {!disabled &&\n (active ? (\n sort.dir === \"asc\" ? (\n <ArrowUp size={12} aria-hidden=\"true\" className=\"shrink-0 text-brand-primaryAction\" />\n ) : (\n <ArrowDown size={12} aria-hidden=\"true\" className=\"shrink-0 text-brand-primaryAction\" />\n )\n ) : (\n <ArrowUpDown\n size={12}\n aria-hidden=\"true\"\n className=\"shrink-0 text-text-tertiary opacity-50 transition-opacity group-hover:opacity-100\"\n />\n ))}\n </button>\n );\n}\n","// Three-state column sorting: the first click sorts by that column, the\n// second reverses it, the third clears the sort and hands the rows back to\n// their natural order. `null` is that third state. Every sortable table\n// cycles this way; keeping it in one place stops the shapes drifting apart.\n\nexport type SortDir = \"asc\" | \"desc\";\n\n/** An active column and direction, or `null` for the unsorted state. */\nexport type SortState<K extends string> = { key: K; dir: SortDir } | null;\n\n/**\n * The state after clicking `key`. `firstDir` is what the column opens on,\n * since the useful first look differs by column: counts and dates want the\n * largest or newest first, names want A→Z.\n */\nexport function cycleSort<K extends string>(\n current: SortState<K>,\n key: K,\n firstDir: SortDir = \"desc\"\n): SortState<K> {\n if (!current || current.key !== key) return { key, dir: firstDir };\n if (current.dir === firstDir) return { key, dir: firstDir === \"desc\" ? \"asc\" : \"desc\" };\n return null;\n}\n\n/**\n * `SortState` in the shape SortButton takes. SortButton wants a non-null\n * object and reads `key: null` as \"no column active\".\n */\nexport function sortProp<K extends string>(sort: SortState<K>): { key: K | null; dir: SortDir } {\n return sort ?? { key: null, dir: \"desc\" };\n}\n\n/**\n * The `aria-sort` value for column `key`'s <th>: \"ascending\"/\"descending\" on\n * the active column, nothing on the rest. aria-sort belongs on the column\n * header, not on the SortButton inside it, and only the sorted column carries it.\n */\nexport function ariaSortFor<K extends string>(\n sort: SortState<K> | { key: K | null; dir: SortDir },\n key: K\n): \"ascending\" | \"descending\" | undefined {\n if (!sort || sort.key !== key) return undefined;\n return sort.dir === \"asc\" ? \"ascending\" : \"descending\";\n}\n","import { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"./cn\";\n\n/** Compact page window: all pages up to 7, otherwise 1 … current±1 … last. */\nexport function pageWindow(current: number, total: number): (number | string)[] {\n if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);\n const keep = new Set([1, total, current, current - 1, current + 1]);\n const pages = [...keep].filter((p) => p >= 1 && p <= total).sort((a, b) => a - b);\n const out: (number | string)[] = [];\n let prev = 0;\n for (const p of pages) {\n if (p - prev > 1) out.push(`gap-${p}`);\n out.push(p);\n prev = p;\n }\n return out;\n}\n\nexport interface PagerProps {\n /** The current page, 1-indexed. */\n page: number;\n totalPages: number;\n onPage: (p: number) => void;\n}\n\n/**\n * @pattern Pager\n * @description Compact prev/next pager with a windowed page-number list —\n * shows every page up to 7 total, otherwise 1 … current±1 … last with\n * ellipsis gaps. Shared by My Exports and Account Matcher.\n * @tokens rounded-control, text-text-secondary, bg-brand-primaryAction, text-brand-onprimary, hover:bg-subtle, hover:text-text-primary, text-text-tertiary\n * @dependencies lucide-react\n * @a11y Page controls are buttons with their own aria-labels, and the current\n * page is marked with aria-current. Don't relabel them with visible text\n * alone -- the labels are what a screen reader announces.\n * @usage\n * ```tsx\n * <Pager page={page} totalPages={totalPages} onPage={setPage} />\n * ```\n */\nexport function Pager({ page, totalPages, onPage }: PagerProps) {\n const btn = \"flex h-8 min-w-8 items-center justify-center rounded-control px-2 text-[13px] transition-colors\";\n return (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => onPage(page - 1)}\n disabled={page === 1}\n aria-label=\"Previous page\"\n className={cn(btn, \"text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30\")}\n >\n <ChevronLeft size={16} />\n </button>\n {pageWindow(page, totalPages).map((p) =>\n typeof p === \"string\" ? (\n <span key={p} className=\"px-1 text-[13px] text-text-tertiary\">\n …\n </span>\n ) : (\n <button\n key={p}\n type=\"button\"\n onClick={() => onPage(p)}\n aria-current={p === page ? \"page\" : undefined}\n className={cn(\n btn,\n p === page\n ? \"bg-brand-primaryAction font-semibold text-brand-onprimary\"\n : \"text-text-secondary hover:bg-subtle hover:text-text-primary\"\n )}\n >\n {p}\n </button>\n )\n )}\n <button\n type=\"button\"\n onClick={() => onPage(page + 1)}\n disabled={page === totalPages}\n aria-label=\"Next page\"\n className={cn(btn, \"text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30\")}\n >\n <ChevronRight size={16} />\n </button>\n </div>\n );\n}\n","import { cn } from \"./cn\";\n\n/**\n * First 1–2 word initials of a workspace name. \"All data workspace\" resolves\n * to \"AD\" through the same rule, so the unscoped default reads as a peer of\n * the named workspaces rather than a special case.\n */\nfunction workspaceInitials(name: string) {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return \"·\";\n if (words.length === 1) return words[0].slice(0, 2).toUpperCase();\n return (words[0][0] + words[1][0]).toUpperCase();\n}\n\nconst SIZES = {\n /** Matches a 15px lucide icon exactly, so a workspace name in a menu row\n * left-aligns with labels in icon-led rows above and below it. */\n xs: \"h-[15px] w-[15px] rounded-[4px] text-[8px] tracking-tight\",\n sm: \"h-6 w-6 text-[10px]\",\n md: \"h-7 w-7 text-[11px]\",\n lg: \"h-11 w-11 text-[15px]\",\n} as const;\n\nexport interface WorkspaceAvatarProps {\n /** Omit for the unscoped \"All data workspace\". */\n name?: string;\n size?: keyof typeof SIZES;\n}\n\n/**\n * @pattern WorkspaceAvatar\n * @description The square tile that identifies a workspace in a switch\n * list — first 1–2 word initials of the workspace name. Pass no name for\n * the unscoped \"All data workspace\", which renders \"AD\" through the same\n * rule so the unscoped default reads as a peer of named workspaces rather\n * than a special case.\n * @tokens rounded-control, bg-subtle, text-text-secondary\n * @usage\n * ```tsx\n * <WorkspaceAvatar name=\"Capital One\" size=\"sm\" />\n * ```\n */\nexport function WorkspaceAvatar({ name, size = \"md\" }: WorkspaceAvatarProps) {\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-control bg-subtle font-semibold leading-none text-text-secondary\",\n SIZES[size]\n )}\n >\n {workspaceInitials(name ?? \"All data\")}\n </span>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"./cn\";\n\nexport interface TagProps {\n /** The tag's text, e.g. \"Digital\". Keep it short: the chip doesn't wrap or truncate. */\n children: ReactNode;\n /** Extra classes merged onto the chip. */\n className?: string;\n}\n\n/**\n * @pattern Tag\n * @description Canonical descriptive tag -- a neutral chip naming what a\n * thing IS: a category, a media type, a focus area. Always neutral, never\n * semantic, never removable.\n *\n * The product separates three jobs that most systems collapse into one, by\n * who authored the label. Badge is the system's view of a thing (status,\n * count, AI-generated) and its colour means something. Tag is the thing\n * describing itself, and stays neutral. FilterChipBar is the user describing\n * what they want to see, and is the only one you can remove.\n * @use when labelling what something is -- a category, a media type, a focus\n * area, a property of the row rather than a judgement about it.\n * @avoid when the colour would mean something. A status, a count, an\n * AI marker or anything the system decided is a Badge.\n * @avoid when the user should be able to dismiss it. An applied filter is a\n * FilterChipBar chip, which belongs to the filter bar rather than to the row.\n * @avoid when there are more than a handful in a row. Tags are scanned, and a\n * dozen neutral chips read as texture rather than as information.\n * @tokens text-micro, bg-subtle, text-text-tertiary, rounded-full\n * @usage\n * ```tsx\n * <Tag>Digital</Tag>\n * ```\n */\nexport function Tag({ children, className }: TagProps) {\n return (\n <span\n className={cn(\n // text-micro and tertiary ink. The component used to sit at 11px in\n // secondary -- a step darker than the ten hand-rolled copies the audit\n // found, which had independently drifted to tertiary. Ten people\n // reaching for \"quieter\" is worth more than the component's original\n // guess: a tag names what a row IS, which is background to the row\n // itself rather than part of it.\n \"inline-flex items-center whitespace-nowrap rounded-full bg-subtle px-2 py-0.5 text-micro font-medium text-text-tertiary\",\n className\n )}\n >\n {children}\n </span>\n );\n}\n","import { ChevronDown, ChevronFirst, ChevronLast, ChevronLeft, ChevronRight } from 'lucide-react'\nimport { cn } from './cn'\nimport { pageWindow } from './Pager'\n\n/**\n * @pattern TablePagination\n * @description Full table-footer pagination bar: a rows-per-page select, a\n * first/prev/pages/next/last pager, and the resolved \"1 – 25 of N results\"\n * range. Owns no state — the host page holds `page` and `perPage` so the\n * paged slice and the bar can't disagree.\n * @tokens rounded-control, border-border-default, bg-input, text-text-primary, text-text-secondary, text-text-tertiary, bg-brand-primaryAction, text-brand-onprimary, hover:bg-subtle, hover:text-text-primary, focus:outline-border-focus\n * @behavior The current page is filled with the brand action color (matching\n * the Contacts pager). First/prev disable on page 1, next/last on the last\n * page — disabled controls stay in the layout so the row never reflows.\n * Changing the per-page count reports it and leaves the host to reset to page\n * 1. With one page of results the pager still renders, so the bar's height\n * and the range readout don't come and go as filters narrow.\n * @a11y A <nav aria-label=\"Pagination\"> wrapping <button> controls, each with\n * its own aria-label (Previous/Next/Last). The chevron icons are aria-\n * hidden, so the labels are the only accessible names -- don't override\n * them with visible text alone.\n * @usage\n * ```tsx\n * <TablePagination\n * page={page}\n * perPage={perPage}\n * totalItems={matching.length}\n * onPageChange={setPage}\n * onPerPageChange={(n) => { setPerPage(n); setPage(1) }}\n * itemLabel=\"results\"\n * />\n * ```\n */\nexport function TablePagination({\n page,\n perPage,\n totalItems,\n onPageChange,\n onPerPageChange,\n perPageOptions = [25, 50, 100],\n itemLabel = 'results',\n className,\n testIdPrefix,\n}: {\n page: number\n perPage: number\n totalItems: number\n onPageChange: (page: number) => void\n onPerPageChange: (perPage: number) => void\n perPageOptions?: number[]\n itemLabel?: string\n className?: string\n /**\n * Optional prefix for `data-testid` attributes on the bar (`testIdPrefix`\n * itself), the per-page select (`-per-page`), the step buttons (`-first`,\n * `-prev`, `-next`, `-last`) and each page button (`-page-<n>`). Omit for no\n * test-id wiring.\n */\n testIdPrefix?: string\n}) {\n const totalPages = Math.max(1, Math.ceil(totalItems / perPage))\n const current = Math.min(page, totalPages)\n const rangeStart = totalItems === 0 ? 0 : (current - 1) * perPage + 1\n const rangeEnd = Math.min(current * perPage, totalItems)\n\n const btn =\n 'flex h-8 min-w-8 items-center justify-center rounded-control px-2 text-[13px] transition-colors'\n const stepBtn = cn(\n btn,\n 'text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30'\n )\n\n return (\n <div className={cn('flex flex-wrap items-center justify-between gap-x-4 gap-y-2', className)} data-testid={testIdPrefix}>\n {/* Rows per page */}\n <label className=\"flex items-center gap-2 text-[13px] text-text-secondary\">\n <span className=\"relative\">\n <select\n value={perPage}\n onChange={(e) => onPerPageChange(Number(e.target.value))}\n aria-label=\"Items per page\"\n data-testid={testIdPrefix && `${testIdPrefix}-per-page`}\n className=\"appearance-none rounded-control border border-border-default bg-input py-1 pl-2.5 pr-7 text-[13px] font-medium text-text-primary focus:outline focus:outline-2 focus:outline-border-focus\"\n >\n {perPageOptions.map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n <ChevronDown\n size={13}\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-text-secondary\"\n />\n </span>\n items per page\n </label>\n\n {/* Pager */}\n <nav className=\"flex items-center gap-1\" aria-label=\"Pagination\">\n <button\n type=\"button\"\n onClick={() => onPageChange(1)}\n disabled={current === 1}\n aria-label=\"First page\"\n data-testid={testIdPrefix && `${testIdPrefix}-first`}\n className={stepBtn}\n >\n <ChevronFirst size={16} aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n onClick={() => onPageChange(current - 1)}\n disabled={current === 1}\n aria-label=\"Previous page\"\n data-testid={testIdPrefix && `${testIdPrefix}-prev`}\n className={stepBtn}\n >\n <ChevronLeft size={16} aria-hidden=\"true\" />\n </button>\n {pageWindow(current, totalPages).map((p) =>\n typeof p === 'string' ? (\n <span key={p} className=\"px-1 text-[13px] text-text-tertiary\">\n …\n </span>\n ) : (\n <button\n key={p}\n type=\"button\"\n data-testid={testIdPrefix && `${testIdPrefix}-page-${p}`}\n onClick={() => onPageChange(p)}\n aria-current={p === current ? 'page' : undefined}\n className={cn(\n btn,\n p === current\n ? 'bg-brand-primaryAction font-semibold text-brand-onprimary'\n : 'text-text-secondary hover:bg-subtle hover:text-text-primary'\n )}\n >\n {p}\n </button>\n )\n )}\n <button\n type=\"button\"\n onClick={() => onPageChange(current + 1)}\n disabled={current === totalPages}\n aria-label=\"Next page\"\n data-testid={testIdPrefix && `${testIdPrefix}-next`}\n className={stepBtn}\n >\n <ChevronRight size={16} aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n onClick={() => onPageChange(totalPages)}\n disabled={current === totalPages}\n aria-label=\"Last page\"\n data-testid={testIdPrefix && `${testIdPrefix}-last`}\n className={stepBtn}\n >\n <ChevronLast size={16} aria-hidden=\"true\" />\n </button>\n </nav>\n\n {/* Range readout */}\n <span className=\"text-[13px] text-text-tertiary tabular-nums\">\n {rangeStart.toLocaleString()} – {rangeEnd.toLocaleString()} of {totalItems.toLocaleString()} {itemLabel}\n </span>\n </div>\n )\n}\n\nexport type TablePaginationProps = Parameters<typeof TablePagination>[0]\n","import { useEffect, useMemo, useRef, useState } from 'react'\nimport { ChevronDown } from 'lucide-react'\nimport { cn } from './cn'\nimport { chipTriggerClass } from './ChipTrigger'\nimport { FilterDropdownFooter } from './FilterDropdownFooter'\n\n/**\n * @pattern DateRangePicker\n * @description Date-range control — the two-line chip (resolved span over\n * the active label, with a chevron) that opens a dropdown of rolling\n * presets plus a Custom Range (From/To month-year selects + Apply). The\n * standard date picker across the app (Sports Dashboard, Account Review,\n * Opportunities, Publisher Intel). The `presets` prop drives which rolling\n * options show — callers pass month, quarter, or year presets (e.g.\n * Publisher Intel keys them to its Time Increment); Creative Intel keeps its\n * own day-level picker (DateRangeFilter).\n * @tokens rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary, hover:bg-subtle, text-brand-primaryAction, bg-input, rounded-control, focus:border-border-focus\n * @dependencies lucide-react\n * @behavior Escape and outside-click both close the popover, resyncing the\n * draft from the last committed value on every open. Without showFooter, any\n * close path commits; with showFooter, only Apply commits and every other\n * close discards the draft.\n * @a11y Trigger is a <button> with aria-expanded and aria-haspopup. The Custom\n * Range selects are native <select> elements, so they keep native keyboard\n * behaviour. Escape closes the popover and discards the draft range.\n * @usage\n * ```tsx\n * <DateRangePicker defaultValue=\"Rolling 6 months\" onChange={setRange} />\n * ```\n */\n\nconst MONTH_ABBR = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\nconst QUARTER_ABBR = ['Q1', 'Q2', 'Q3', 'Q4']\n\n/** What the Custom Range From/To selects pick. */\nexport type DateGranularity = 'month' | 'quarter' | 'year'\nconst PRESETS = ['Rolling 3 months', 'Rolling 6 months', 'Rolling 12 months']\n\nconst startOfToday = () => {\n const d = new Date()\n return new Date(d.getFullYear(), d.getMonth(), d.getDate())\n}\nconst fmtDate = (d: Date) => d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n\n/** Resolve a label to its actual [start, end] span, ending at `today`. */\nexport function resolveRange(label: string, today: Date = startOfToday()): [Date, Date] {\n const end = today\n const mMonths = label.match(/Rolling (\\d+) months/)\n if (mMonths) {\n return [new Date(end.getFullYear(), end.getMonth() - Number(mMonths[1]), 1), end]\n }\n const mQuarters = label.match(/Rolling (\\d+) quarters/)\n if (mQuarters) {\n return [new Date(end.getFullYear(), end.getMonth() - Number(mQuarters[1]) * 3, 1), end]\n }\n const mYears = label.match(/Rolling (\\d+) years/)\n if (mYears) {\n return [new Date(end.getFullYear() - Number(mYears[1]), end.getMonth(), 1), end]\n }\n const mCustom = label.match(/([A-Za-z]{3})\\s+(\\d{4}).*?([A-Za-z]{3})\\s+(\\d{4})/)\n if (mCustom) {\n const s = new Date(Number(mCustom[2]), MONTH_ABBR.indexOf(mCustom[1]), 1)\n const e = new Date(Number(mCustom[4]), MONTH_ABBR.indexOf(mCustom[3]) + 1, 0)\n return [s, e]\n }\n return [new Date(end.getFullYear(), end.getMonth() - 6, 1), end]\n}\n\n/** \"Dec 1, 2025 – Jun 25, 2026\" for a label. */\nfunction spanLabel(label: string, today: Date): string {\n const [s, e] = resolveRange(label, today)\n return `${fmtDate(s)} – ${fmtDate(e)}`\n}\n\nfunction MiniSelect<T extends string | number>({ value, onChange, options }: { value: T; onChange: (v: T) => void; options: { label: string; value: T }[] }) {\n return (\n <select\n value={String(value)}\n onChange={(e) => {\n const opt = options.find((o) => String(o.value) === e.target.value)\n if (opt) onChange(opt.value)\n }}\n className=\"rounded-control border border-border-default bg-input px-1.5 py-1 text-[12px] text-text-primary outline-hidden focus:border-border-focus\"\n >\n {options.map((o) => (\n <option key={String(o.value)} value={String(o.value)}>{o.label}</option>\n ))}\n </select>\n )\n}\n\nexport function DateRangePicker({\n defaultValue = 'Rolling 6 months',\n granularity = 'month',\n align = 'left',\n presets = PRESETS,\n onChange,\n onRangeChange,\n showFooter = false,\n today,\n years,\n}: {\n defaultValue?: string\n align?: 'left' | 'right'\n /**\n * What the Custom Range From/To selects pick. `month` shows month + year\n * selects, `quarter` shows quarter + year, `year` shows year alone -- and\n * the applied label follows suit. Pair it with matching `presets`.\n */\n granularity?: DateGranularity\n /** Rolling presets shown above Custom Range. Defaults to 3/6/12 months. */\n presets?: string[]\n onChange?: (label: string) => void\n /** Reports the resolved start/end dates — used to drive dependent views (e.g. table columns). */\n onRangeChange?: (start: Date, end: Date) => void\n /** Deferred mode: preset/custom-range picks stage in a draft; only the fixed\n * Apply footer commits it (no live commit on click). */\n showFooter?: boolean\n /** End of the available data window: rolling presets resolve back from here.\n * Defaults to the current date. */\n today?: Date\n /** Years offered in the Custom Range selects. Defaults to the last four,\n * ending with `today`'s year. */\n years?: number[]\n}) {\n const end = useMemo(() => today ?? startOfToday(), [today])\n const yearOptions = years ?? [3, 2, 1, 0].map((n) => end.getFullYear() - n)\n const [open, setOpen] = useState(false)\n const [value, setValue] = useState(defaultValue)\n // Draft label staged while the dropdown is open in footer mode — the trigger\n // keeps showing `value` (the committed range) until Apply commits the draft.\n const [draft, setDraft] = useState(defaultValue)\n const ref = useRef<HTMLDivElement>(null)\n // Custom Range opens on the year ending at `today`'s month.\n const [fromMo, setFromMo] = useState(end.getMonth())\n const [fromYr, setFromYr] = useState(end.getFullYear() - 1)\n const [toMo, setToMo] = useState(end.getMonth())\n const [toYr, setToYr] = useState(end.getFullYear())\n const [fromQ, setFromQ] = useState(Math.floor(end.getMonth() / 3))\n const [toQ, setToQ] = useState(Math.floor(end.getMonth() / 3))\n\n // Emit the resolved range on mount and whenever the committed value changes,\n // so range-driven consumers (e.g. Sports month columns) stay in sync.\n useEffect(() => {\n const [s, e] = resolveRange(value, end)\n onRangeChange?.(s, e)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value])\n\n const toggleOpen = () => {\n if (!open) setDraft(value) // resync the draft from the last applied state on every open\n setOpen((o) => !o)\n }\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n const onKey = (e: KeyboardEvent) => e.key === 'Escape' && setOpen(false)\n window.addEventListener('mousedown', onDown)\n window.addEventListener('keydown', onKey)\n return () => { window.removeEventListener('mousedown', onDown); window.removeEventListener('keydown', onKey) }\n }, [open])\n\n const commit = (label: string) => { setValue(label); onChange?.(label); setOpen(false) }\n\n // Span in whole periods at the active granularity -- 1 or more means From\n // isn't past To.\n const span =\n granularity === 'year'\n ? toYr - fromYr + 1\n : granularity === 'quarter'\n ? toYr * 4 + toQ - (fromYr * 4 + fromQ) + 1\n : toYr * 12 + toMo - (fromYr * 12 + fromMo) + 1\n const valid = span >= 1\n const applyCustom = () => {\n if (!valid) return\n const label =\n granularity === 'year'\n ? `${fromYr} – ${toYr}`\n : granularity === 'quarter'\n ? `${QUARTER_ABBR[fromQ]} ${fromYr} – ${QUARTER_ABBR[toQ]} ${toYr}`\n : `${MONTH_ABBR[fromMo]} ${fromYr} – ${MONTH_ABBR[toMo]} ${toYr}`\n if (showFooter) setDraft(label)\n else commit(label)\n }\n\n return (\n <div className=\"relative\" ref={ref}>\n <button\n type=\"button\"\n onClick={toggleOpen}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n className={chipTriggerClass()}\n >\n <span className=\"flex flex-col gap-1 text-left leading-none\">\n <span className=\"text-[10px] text-text-tertiary\">{spanLabel(value, end)}</span>\n <span className=\"text-[12px] font-medium text-text-primary\">{value}</span>\n </span>\n <ChevronDown size={14} aria-hidden=\"true\" className={cn('shrink-0 text-text-secondary transition-transform', open && 'rotate-180')} />\n </button>\n {open && (\n <div className={cn('absolute top-[calc(100%+8px)] z-30 w-[280px] overflow-hidden rounded-card border border-border-default bg-surface py-1 shadow-overlay', align === 'right' ? 'right-0' : 'left-0')}>\n {presets.map((p) => (\n <button\n key={p}\n type=\"button\"\n onClick={() => (showFooter ? setDraft(p) : commit(p))}\n className={cn('block w-full px-3 py-2 text-left text-[13px] transition-colors hover:bg-subtle', (showFooter ? draft : value) === p ? 'font-semibold text-brand-primaryAction' : 'text-text-secondary')}\n >\n {p}\n </button>\n ))}\n <div className=\"mt-1 border-t border-border-default px-3 pb-2 pt-2\">\n <div className=\"text-[13px] font-semibold text-text-primary\">Custom Range</div>\n <div className=\"mt-2 flex flex-col gap-2\">\n <label className=\"flex items-center justify-between gap-2 text-[12px] text-text-secondary\">\n From\n <span className=\"flex gap-1\">\n {granularity === 'month' && (\n <MiniSelect value={fromMo} onChange={setFromMo} options={MONTH_ABBR.map((mm, i) => ({ label: mm, value: i }))} />\n )}\n {granularity === 'quarter' && (\n <MiniSelect value={fromQ} onChange={setFromQ} options={QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i }))} />\n )}\n <MiniSelect value={fromYr} onChange={setFromYr} options={yearOptions.map((y) => ({ label: String(y), value: y }))} />\n </span>\n </label>\n <label className=\"flex items-center justify-between gap-2 text-[12px] text-text-secondary\">\n To\n <span className=\"flex gap-1\">\n {granularity === 'month' && (\n <MiniSelect value={toMo} onChange={setToMo} options={MONTH_ABBR.map((mm, i) => ({ label: mm, value: i }))} />\n )}\n {granularity === 'quarter' && (\n <MiniSelect value={toQ} onChange={setToQ} options={QUARTER_ABBR.map((qq, i) => ({ label: qq, value: i }))} />\n )}\n <MiniSelect value={toYr} onChange={setToYr} options={yearOptions.map((y) => ({ label: String(y), value: y }))} />\n </span>\n </label>\n <button\n type=\"button\"\n onClick={applyCustom}\n disabled={!valid}\n className=\"self-start text-[13px] font-semibold text-brand-primaryAction transition-opacity hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {showFooter ? 'Use custom range' : 'Apply'}\n </button>\n </div>\n </div>\n {showFooter && <FilterDropdownFooter onApply={() => commit(draft)} />}\n </div>\n )}\n </div>\n )\n}\n\nexport type DateRangePickerProps = Parameters<typeof DateRangePicker>[0]\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { ChevronDown, Check, Minus, Search, X } from 'lucide-react'\nimport { cn } from './cn'\nimport { chipTriggerClass, ChipContent, type ChipVariant } from './ChipTrigger'\nimport { FilterDropdownFooter } from './FilterDropdownFooter'\n\nexport interface MultiSelectGroup {\n id: string\n label: string\n children: { id: string; label: string }[]\n}\n\n/**\n * @pattern MultiSelectFilter\n * @description Quick-access multi-select chip — mirrors the DateRangeFilter\n * button shape (two-line caption + value with a chevron) and opens a\n * searchable checkbox popover. Used for the page-level Media Type /\n * Advertiser filters that share state with the filter tray.\n * @tokens rounded-control, rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary, text-text-link, border-border-interactive, bg-brand-primaryAction, bg-input, hover:bg-subtle, hover:text-text-primary, placeholder:text-text-tertiary, text-brand-onprimary\n * @dependencies lucide-react\n * @behavior `variant` picks the trigger's chip stroke: `box` (default, the\n * boxed two-line chip on the default border) or `inline` (same fill,\n * darker stroke, for chips sitting directly on the canvas). Left out of\n * the catalog's variant list deliberately: check-prop-drift can't resolve\n * the imported ChipVariant alias through this component's inline prop\n * type, so such a tag would be unvalidated -- and this exact component\n * has had stale ones stripped before.\n * Same draft/commit-on-close pattern as AdvertiserQuickFilter — the\n * draft resyncs from `selected` every time the tray opens, and (without\n * showFooter) any close path commits it, while showFooter mode requires the\n * Apply button and discards the draft on every other close. `min` enforces a\n * selection floor by silently ignoring any toggle that would drop below it —\n * there's no error state, the click just does nothing. Group parents are\n * tri-state and toggle all of their children in one action.\n * @a11y Trigger is a <button> with aria-expanded; the menu is role=\"dialog\" and\n * Escape closes it. Option rows carry their own checkbox semantics. Focus\n * is not moved into the menu on open, so keyboard users tab into it in DOM\n * order.\n * @usage\n * ```tsx\n * <MultiSelectFilter caption=\"Media\" options={mediaOptions} selected={selected} onChange={setSelected} />\n * ```\n */\nexport function MultiSelectFilter({\n caption,\n options = [],\n groups,\n counts,\n variant = 'box',\n selected,\n onChange,\n allLabel = 'All',\n searchable = false,\n searchPlaceholder,\n align = 'left',\n fullIsAll = false,\n min = 0,\n icon,\n showFooter = false,\n clearValue = [],\n menuWidthClass = 'w-60',\n plainParent = false,\n fullWidth = false,\n}: {\n caption: string\n /**\n * Live option-id -> result count. Supplying it makes the menu faceted:\n * every label gets a \"(n)\" suffix and options with nothing behind them\n * drop out. A selected option is always kept, or there would be no way to\n * undo it.\n */\n counts?: Record<string, number>\n /** Chip stroke for the trigger. See ChipVariant. */\n variant?: ChipVariant\n options?: { id: string; label: string }[]\n /** When provided, renders a nested parent → children tree (selection tracks\n * leaf ids; parents are tri-state and toggle all their children). */\n groups?: MultiSelectGroup[]\n selected: string[]\n onChange: (next: string[]) => void\n allLabel?: string\n searchable?: boolean\n /** Overrides the search box's placeholder. The default derives from the\n * caption, which reads wrong once a caption is singular (\"Search topic\"). */\n searchPlaceholder?: string\n align?: 'left' | 'right'\n /** Treat \"all options selected\" as the unfiltered \"All\" state in the label. */\n fullIsAll?: boolean\n /** Minimum selections that must remain (a toggle that would drop below is ignored). */\n min?: number\n icon?: React.ReactNode\n /** Deferred mode: checkbox edits stage in a draft; only the fixed Apply/Clear\n * All footer commits or discards them (no live commit on close). */\n showFooter?: boolean\n /** What \"Clear all\" resets the draft to — the page's default selection. */\n clearValue?: string[]\n /** Tailwind width class for the dropdown panel (default `w-60`). Widen it when\n * option labels are long and would otherwise wrap. */\n menuWidthClass?: string\n /** Render group parents at normal weight instead of semibold. */\n plainParent?: boolean\n /** Stretch the trigger (and, with `menuWidthClass=\"w-full\"`, the panel) to fill\n * its container — for stacked/full-width form layouts instead of the chip bar. */\n fullWidth?: boolean\n}) {\n // Flat list of selectable leaves — the source of truth for label + \"all\".\n // A childless group (a flat parent, e.g. \"Outdoor\") acts as its own leaf.\n const groupLeaves = (g: MultiSelectGroup) => (g.children.length ? g.children : [{ id: g.id, label: g.label }])\n const leafOptions = groups ? groups.flatMap(groupLeaves) : options\n const [open, setOpen] = useState(false)\n const [q, setQ] = useState('')\n // Draft buffers selections while open; we only commit to onChange on close so\n // the page isn't re-filtered on every toggle.\n const [draft, setDraft] = useState<string[]>(selected)\n const ref = useRef<HTMLDivElement>(null)\n\n // Close commits the draft (if it changed) — single place all close paths funnel through.\n // In footer mode, closing (outside click / Escape / re-click) never commits —\n // only the Apply button does — so the trigger label never previews the draft.\n const close = useCallback(() => {\n setOpen(false)\n setQ('')\n if (showFooter) return\n if (draft.length !== selected.length || draft.some((id) => !selected.includes(id))) {\n onChange(draft)\n }\n }, [draft, selected, onChange, showFooter])\n\n const openTray = () => {\n setDraft(selected) // resync from latest applied state\n setOpen(true)\n }\n\n const apply = () => {\n onChange(draft)\n setOpen(false)\n setQ('')\n }\n\n useEffect(() => {\n if (!open) return\n const onKey = (e: KeyboardEvent) => e.key === 'Escape' && close()\n const onClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) close()\n }\n window.addEventListener('keydown', onKey)\n window.addEventListener('mousedown', onClick)\n return () => {\n window.removeEventListener('keydown', onKey)\n window.removeEventListener('mousedown', onClick)\n }\n }, [open, close])\n\n const toggle = (id: string) =>\n setDraft((cur) => {\n const next = cur.includes(id) ? cur.filter((x) => x !== id) : [...cur, id]\n if (next.length < min) return cur // honor minimum (e.g. Media needs ≥1)\n return next\n })\n\n // Parent (group) toggle — selects/deselects all of a group's leaves at once.\n const toggleGroup = (g: MultiSelectGroup) =>\n setDraft((cur) => {\n // Never bulk-select a leaf that has nothing behind it (but always allow\n // deselecting one that's somehow already picked).\n const ids = groupLeaves(g)\n .map((c) => c.id)\n .filter((id) => !counts || (counts[id] ?? 0) > 0 || cur.includes(id))\n if (!ids.length) return cur\n const allSel = ids.every((id) => cur.includes(id))\n const next = allSel ? cur.filter((id) => !ids.includes(id)) : [...new Set([...cur, ...ids])]\n if (next.length < min) return cur\n return next\n })\n\n /** An option is listed only while something is behind it. A selected option\n * is always listed, or there'd be no way to undo it. */\n const isAvailable = (id: string) => !counts || (counts[id] ?? 0) > 0 || draft.includes(id)\n const countFor = (id: string) => counts?.[id] ?? 0\n\n const groupState = (g: MultiSelectGroup): 'none' | 'some' | 'all' => {\n const ids = groupLeaves(g).map((c) => c.id).filter(isAvailable)\n if (!ids.length) return 'none'\n const sel = ids.filter((id) => draft.includes(id)).length\n return sel === 0 ? 'none' : sel === ids.length ? 'all' : 'some'\n }\n\n // The chip reflects the draft while open (live preview) and applied state when\n // closed — except in footer mode, where it always reflects the last applied\n // state so nothing changes until Apply is clicked.\n const shown = open && !showFooter ? draft : selected\n const isAll = shown.length === 0 || (fullIsAll && shown.length === leafOptions.length)\n const value = isAll\n ? allLabel\n : shown.length === 1\n ? leafOptions.find((o) => o.id === shown[0])?.label ?? `${shown.length} selected`\n : `${shown.length} selected`\n\n const ql = q.trim().toLowerCase()\n const items = options.filter((o) => isAvailable(o.id) && (!ql || o.label.toLowerCase().includes(ql)))\n // Grouped search: a group whose label matches keeps all its children; otherwise\n // only its matching children are shown (group hidden when nothing matches).\n const visibleGroups: MultiSelectGroup[] = groups\n ? groups\n .map((g): MultiSelectGroup | null => {\n const live = g.children.filter((c) => isAvailable(c.id))\n if (!live.length && !isAvailable(g.id)) return null\n if (!ql || g.label.toLowerCase().includes(ql)) return { ...g, children: live }\n const kids = live.filter((c) => c.label.toLowerCase().includes(ql))\n return kids.length ? { ...g, children: kids } : null\n })\n .filter((g): g is MultiSelectGroup => g !== null)\n : []\n\n return (\n <div className={cn('relative', fullWidth && 'w-full')} ref={ref}>\n <button\n type=\"button\"\n onClick={() => (open ? close() : openTray())}\n aria-expanded={open}\n className={cn(chipTriggerClass(variant), fullWidth && 'w-full justify-between')}\n >\n <ChipContent caption={caption} value={value} icon={icon} />\n <ChevronDown\n size={14}\n aria-hidden=\"true\"\n className={cn('shrink-0 text-text-secondary transition-transform', open && 'rotate-180')}\n />\n </button>\n\n {open && (\n <div\n className={cn(\n 'absolute top-[calc(100%+8px)] z-30 flex flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay',\n menuWidthClass,\n align === 'right' ? 'right-0' : 'left-0'\n )}\n role=\"dialog\"\n aria-label={caption}\n >\n {searchable && (\n <div className=\"border-b border-border-default p-2\">\n <div className=\"flex h-9 items-center gap-2 rounded-control border border-border-default bg-input px-2.5\">\n <Search size={14} className=\"text-text-secondary\" aria-hidden=\"true\" />\n <input\n type=\"text\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={searchPlaceholder ?? `Search ${caption.toLowerCase()}`}\n className=\"h-full flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary\"\n />\n {q && (\n <button type=\"button\" onClick={() => setQ('')} aria-label=\"Clear search\" className=\"text-text-tertiary hover:text-text-primary\">\n <X size={13} />\n </button>\n )}\n </div>\n </div>\n )}\n <div className=\"max-h-[280px] overflow-y-auto p-1\">\n {groups\n ? visibleGroups.map((g) => {\n const state = groupState(g)\n return (\n <div key={g.id}>\n {/* Parent — tri-state; toggles all of its children. */}\n <button\n type=\"button\"\n onClick={() => toggleGroup(g)}\n className=\"flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle\"\n >\n <TriCheck state={state} />\n <span className={cn('flex-1 text-[14px] text-text-primary', !plainParent && 'font-semibold')}>{g.label}</span>\n {counts && <OptionCount n={countFor(g.id)} />}\n </button>\n {/* Children — indented under the parent. */}\n {g.children.map((c) => {\n const checked = draft.includes(c.id)\n return (\n <button\n key={c.id}\n type=\"button\"\n onClick={() => toggle(c.id)}\n className=\"flex w-full items-center gap-2.5 rounded-control py-2 pl-9 pr-2 text-left transition-colors hover:bg-subtle\"\n >\n <TriCheck state={checked ? 'all' : 'none'} />\n <span className=\"flex-1 text-[14px] text-text-primary\">{c.label}</span>\n {counts && <OptionCount n={countFor(c.id)} />}\n </button>\n )\n })}\n </div>\n )\n })\n : items.map((o) => {\n const checked = draft.includes(o.id)\n return (\n <button\n key={o.id}\n type=\"button\"\n onClick={() => toggle(o.id)}\n className=\"flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle\"\n >\n <span\n className={cn(\n 'flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors',\n checked\n ? 'border-transparent bg-brand-primaryAction text-brand-onprimary'\n : 'border-border-interactive bg-input'\n )}\n >\n {checked && <Check size={13} strokeWidth={3} />}\n </span>\n <span className=\"flex-1 text-[14px] text-text-primary\">{o.label}</span>\n {counts && <OptionCount n={countFor(o.id)} />}\n </button>\n )\n })}\n {((groups && !visibleGroups.length) || (!groups && !items.length)) && (\n <div className=\"py-6 text-center text-[13px] text-text-tertiary\">No matches.</div>\n )}\n </div>\n {showFooter ? (\n <FilterDropdownFooter onClear={() => setDraft(clearValue)} onApply={apply} />\n ) : (\n min === 0 && draft.length > 0 && (\n <div className=\"border-t border-border-default p-2\">\n <button\n type=\"button\"\n onClick={() => setDraft([])}\n className=\"text-[12px] font-medium text-text-link hover:underline\"\n >\n Clear {caption.toLowerCase()}\n </button>\n </div>\n )\n )}\n </div>\n )}\n </div>\n )\n}\n\n/** Checkbox visual supporting a tri-state: all (check), some (dash), none (empty). */\nfunction TriCheck({ state }: { state: 'none' | 'some' | 'all' }) {\n const filled = state !== 'none'\n return (\n <span\n className={cn(\n 'flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors',\n filled\n ? 'border-transparent bg-brand-primaryAction text-brand-onprimary'\n : 'border-border-interactive bg-input'\n )}\n >\n {state === 'all' && <Check size={13} strokeWidth={3} />}\n {state === 'some' && <Minus size={13} strokeWidth={3} />}\n </span>\n )\n}\n\nexport type MultiSelectFilterProps = Parameters<typeof MultiSelectFilter>[0]\n\n/** Result count shown after an option label in faceted mode. */\nfunction OptionCount({ n }: { n: number }) {\n return <span className=\"shrink-0 text-[12px] tabular-nums text-text-tertiary\">({n.toLocaleString()})</span>\n}\n","import { cn } from \"./cn\";\n\n/**\n * Track, knob and travel per size. The knob leaves a 2px gutter at each end, so\n * its \"on\" offset is always track − knob − 2 — keep that relationship if a new\n * size is added, or the knob will sit off-centre at one end.\n */\nconst SIZES = {\n sm: { track: \"h-5 w-9\", knob: \"h-4 w-4\", on: \"translate-x-[18px]\" },\n md: { track: \"h-6 w-11\", knob: \"h-5 w-5\", on: \"translate-x-[22px]\" },\n} as const;\n\nexport interface ToggleProps {\n /** Whether the switch is on. Controlled: the parent owns this value. */\n checked: boolean;\n /** Receives the value being switched TO, not the current one. */\n onChange: (next: boolean) => void;\n /** Accessible name; the visible label lives in the row around it. */\n label: string;\n /** `md` for settings rows where the switch is the subject; `sm` for dense rows next to 13px text. */\n size?: keyof typeof SIZES;\n /** Blocks clicks and dims the switch to 50% opacity. */\n disabled?: boolean;\n /** Extra classes merged onto the track (the outer `<button>`). */\n className?: string;\n /** Optional prefix for the switch's `data-testid` (`${testIdPrefix}-toggle`). Omit for no test-id wiring. */\n testIdPrefix?: string;\n}\n\n/**\n * @pattern Toggle\n * @description The app's on/off switch. Use it for a setting that takes effect\n * as a state the user keeps — \"only include enriched creatives\", \"email me a\n * digest\" — where a checkbox would read as an item being ticked off a list.\n * Rendered as a `<button role=\"switch\">` so the on/off state is announced as a\n * switch rather than a checkbox, and so the track and knob can carry the brand\n * fill without fighting a native input's styling hooks.\n * @tokens bg-brand-primaryAction, bg-border-interactive, bg-surface, shadow-raised, outline-border-focus\n * @behavior The knob is positioned by `translate-x`, not by flex alignment, so\n * the slide animates. Off uses `bg-border-interactive` rather than a grey\n * literal, which keeps the track visible against `bg-surface` in dark mode.\n * Pair it with a label and any InfoTip in the surrounding row: this component\n * draws only the switch, so rows stay free to lay the label out however they\n * need (usually label left, switch pushed right).\n * @variant md - Settings panels and modals, where the switch is the row's subject.\n * @variant sm - Dense rows next to 13px body text, where the md track overpowers its own label.\n * @a11y The <button> carries role=\"switch\" and aria-checked, so it is the\n * control -- don't nest it in another interactive element. `label`\n * supplies the accessible name; without it the switch is announced\n * unlabelled.\n * @usage\n * ```tsx\n * <Toggle checked={enabled} onChange={setEnabled} label=\"Email news alerts\" />\n * <Toggle size=\"sm\" checked={enabled} onChange={setEnabled} label=\"Only include enriched creatives\" />\n * ```\n */\nexport function Toggle({ checked, onChange, label, size = \"md\", disabled, className, testIdPrefix }: ToggleProps) {\n const s = SIZES[size];\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-label={label}\n disabled={disabled}\n data-testid={testIdPrefix && `${testIdPrefix}-toggle`}\n onClick={() => onChange(!checked)}\n className={cn(\n \"relative inline-flex shrink-0 items-center rounded-full transition-colors focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus\",\n s.track,\n checked ? \"bg-brand-primaryAction\" : \"bg-border-interactive\",\n disabled && \"cursor-not-allowed opacity-50\",\n className\n )}\n >\n <span\n className={cn(\n \"inline-block transform rounded-full bg-surface shadow-raised transition-transform\",\n s.knob,\n checked ? s.on : \"translate-x-0.5\"\n )}\n />\n </button>\n );\n}\n","\"use client\";\n\nimport { useId } from \"react\";\nimport { Sparkles } from \"lucide-react\";\n\nexport interface AISparkProps {\n size?: number;\n className?: string;\n}\n\n/**\n * @pattern AISpark\n * @description Assistant glyph — the lucide Sparkles icon stroked with the\n * MR orange→violet assistant gradient. Each instance scopes its own gradient\n * id, and the stops follow light/dark mode.\n * @dependencies lucide-react\n * @usage\n * ```tsx\n * <AISpark size={14} />\n * ```\n */\nexport function AISpark({ size = 16, className }: AISparkProps) {\n const id = useId();\n return (\n <>\n <svg width=\"0\" height=\"0\" aria-hidden=\"true\" style={{ position: \"absolute\" }}>\n <defs>\n <linearGradient id={id} x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"var(--mr-color-brand-primary)\" />\n {/* The violet end is a literal: @mediaradar/design-tokens has no\n assistant token yet. Same light/dark values as\n insights-studio-prototype's local --color-assistant-to; the dark\n one keys off data-theme, the attribute design-tokens' dark.css uses. */}\n <stop offset=\"100%\" className=\"[stop-color:#9474ff] in-data-[theme=dark]:[stop-color:#a488ff]\" />\n </linearGradient>\n </defs>\n </svg>\n <Sparkles size={size} stroke={`url(#${id})`} className={className} aria-hidden=\"true\" />\n </>\n );\n}\n","import { cn } from \"./cn\";\n\nexport type FreshnessLevel = \"fresh\" | \"recent\" | \"stale\";\n\nconst dotColor: Record<FreshnessLevel, string> = {\n fresh: \"bg-status-success\",\n recent: \"bg-status-warning\",\n stale: \"bg-text-tertiary\",\n};\n\nconst srLabel: Record<FreshnessLevel, string> = {\n fresh: \"Fresh (under 4 hours)\",\n recent: \"Recent (today)\",\n stale: \"Older than a day\",\n};\n\nexport interface FreshnessProps {\n level: FreshnessLevel;\n}\n\n/**\n * @pattern Freshness\n * @description Freshness dot — prefixed to card meta rows so a row of 4\n * timestamps stops reading as a wall of identical text. Color carries the\n * urgency signal at a glance.\n * @tokens bg-status-success, bg-status-warning, bg-text-tertiary\n * @a11y role=\"img\" with an aria-label per level, so the dot has a text\n * alternative rather than announcing as decoration. The label is the only\n * thing a screen reader gets -- the colour carries no meaning on its own.\n * @usage\n * ```tsx\n * <Freshness level=\"fresh\" />\n * ```\n */\nexport function Freshness({ level }: FreshnessProps) {\n return (\n <span\n className={cn(\"inline-block h-1.5 w-1.5 shrink-0 rounded-full\", dotColor[level])}\n role=\"img\"\n aria-label={srLabel[level]}\n />\n );\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","Search","jsx","jsxs","Fragment","jsx","jsxs","useState","useRef","useEffect","Search","jsx","jsxs","jsx","jsxs","Check","jsx","Check","useEffect","useMemo","useRef","useState","ChevronDown","jsx","jsxs","slug","useEffect","useRef","useState","Check","ChevronDown","Search","Fragment","jsx","jsxs","cx","useRef","ChevronLeft","ChevronRight","jsx","jsxs","useEffect","useRef","useState","Check","ChevronDown","jsx","jsxs","cx","useState","useRef","useEffect","ChevronDown","Check","useCallback","useEffect","useRef","useState","createPortal","Check","ChevronDown","jsx","jsxs","cx","slug","jsx","jsxs","Card","jsx","jsxs","useEffect","useRef","useState","ChevronDown","X","jsx","jsxs","cx","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","useEffect","useLayoutEffect","useRef","useState","createPortal","jsx","jsxs","cx","jsx","jsxs","ListChecks","jsx","jsxs","ChevronDown","jsx","jsxs","cx","useCallback","useEffect","useLayoutEffect","useMemo","useRef","useState","createPortal","Search","Info","ChevronRight","ChevronDown","Check","Fragment","jsx","jsxs","cx","slug","useState","useMemo","Search","ChevronRight","Info","Check","useRef","useCallback","useLayoutEffect","useEffect","ChevronDown","createPortal","useState","jsx","jsxs","cx","forwardRef","Loader2","jsx","jsxs","forwardRef","Loader2","jsx","jsxs","useEffect","useState","createPortal","jsx","jsxs","useState","useEffect","createPortal","jsx","jsxs","X","jsx","jsxs","X","jsx","jsxs","ChevronLeft","ChevronRight","jsx","jsxs","ChevronLeft","ChevronRight","jsx","jsx","ChevronDown","ChevronLeft","ChevronRight","jsx","jsxs","ChevronDown","ChevronLeft","ChevronRight","useEffect","useMemo","useRef","useState","ChevronDown","jsx","jsxs","useMemo","useState","useRef","useEffect","ChevronDown","useCallback","useEffect","useRef","useState","ChevronDown","Check","Minus","Search","X","jsx","jsxs","useState","useRef","useCallback","useEffect","ChevronDown","Search","X","Check","Minus","jsx","SIZES","useId","Fragment","jsx","jsxs","jsx"]}