@behindthemusictree/app-kit-ui 42.0.1 → 43.0.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/popup/PopupTitle.tsx","../src/popup/PopupButtons.tsx","../src/popup/BasePopup.tsx","../src/popup/Toast.tsx","../src/popup/TrackUploadPopup.tsx","../src/popup/AuthErrorPopup.tsx","../src/popup/InternalErrorPopup.tsx","../src/popup/NetworkErrorPopup.tsx","../src/popup/AuthPopup.tsx","../src/popup/SpotifyAuthErrorPopup.tsx","../src/auth/AuthCallbackHandler.tsx","../src/genre-tree/GenreTreeView.tsx","../src/genre-tree/playlist-tree/size-metric.ts","../src/genre-tree/playlist-tree/toTreeNodes.ts","../src/genre-tree/playlist-tree/toGenreNodeStyles.ts","../src/genre-tree/playlist-tree/TreePerRoot.tsx","../src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx","../src/genre-tree/playlist-tree/TreeWheel.tsx","../src/genre-tree/playlist-tree/TreeWheelRadialPopCore.tsx","../src/genre-tree/GenreTreeWheelHandoff.tsx","../src/genre-tree/GenreTreeSearch.tsx","../src/genre-tree/GenreSearch.tsx","../src/genre-tree/search/SearchBox.tsx","../src/genre-tree/search/SearchGroup.ts","../src/genre-tree/search/useArtistSearchGroup.tsx","../src/genre-tree/search/useSongSearchGroup.tsx","../src/genre-tree/search/useGenreRemoteSearchGroup.tsx","../src/genre-tree/GenreDetailPanel.tsx","../src/genre-tree/GenreInfoPanelBody.tsx","../src/genre-tree/GenreActionBand.tsx","../src/genre-tree/ShareActionButton.tsx","../src/genre-tree/SharePopup.tsx","../src/genre-tree/ShareDestinationButton.tsx","../src/genre-tree/SharePreviewCard.tsx","../src/genre-tree/GenrePlayActions.tsx","../src/genre-tree/RegionGlobeIcon.tsx","../src/genre-tree/regionGlobePaths.ts","../src/genre-tree/treeMarkPath.ts","../src/genre-tree/TreeMarkIcon.tsx","../src/genre-tree/GenreDetailExtras.tsx","../src/genre-tree/ClampedText.tsx","../src/genre-tree/CommonsPhoto.tsx","../src/genre-tree/GenrePlaylistTracks.tsx","../src/genre-tree/MusicBrainzRecordingLink.tsx","../src/genre-tree/ChangeParentPopup.tsx","../src/genre-tree/artist/useArtistPanel.tsx","../src/genre-tree/artist/ArtistActionBand.tsx","../src/genre-tree/artist/ArtistHeader.tsx","../src/genre-tree/artist/ArtistLinks.tsx","../src/genre-tree/artist/formatYears.ts","../src/genre-tree/artist/ArtistPhoto.tsx","../src/genre-tree/artist/ArtistMembers.tsx","../src/genre-tree/artist/ArtistDiscography.tsx","../src/genre-tree/artist/ArtistSongs.tsx","../src/genre-tree/track-list-sidebar/TrackItem.tsx","../src/genre-tree/TrackPositionPlayPause.tsx","../src/genre-tree/song/useSongPanel.tsx","../src/genre-tree/song/SongPanelContent.tsx","../src/genre-tree/useEntityPanel.tsx","../src/genre-tree/SizeMetricToggle.tsx","../src/genre-tree/index.ts","../src/genre-tree/track-list-sidebar/TrackListSidebar.tsx","../src/genre-tree/PlayerPanel.tsx","../src/genre-tree/PlayerControls.tsx","../src/genre-tree/Rating.tsx","../src/genre-tree/EntityDetailPanel.tsx"],"sourcesContent":["export * from \"./popup\";\nexport * from \"./auth\";\nexport * from \"./genre-tree\";\n","\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\ninterface PopupTitleProps {\n title: string;\n onClose: () => void;\n isDismissable?: boolean;\n icon?: LucideIcon;\n className?: string;\n titleClassName?: string;\n closeButtonClassName?: string;\n}\n\nexport function PopupTitle({\n title,\n onClose,\n isDismissable,\n icon: Icon,\n className = \"\",\n titleClassName = \"\",\n closeButtonClassName = \"\",\n}: PopupTitleProps) {\n return (\n <div className={`popup-title flex items-center justify-between bg-black p-4 rounded-t-lg ${className}`}>\n <div className=\"flex items-center gap-2\">\n {Icon && <Icon className=\"h-5 w-5 text-white\" />}\n <h3 id=\"popup-title\" className={`text-white font-semibold ${titleClassName}`}>\n {title}\n </h3>\n </div>\n {isDismissable && (\n <Button\n onClick={onClose}\n className={`h-8 w-8 text-white hover:text-white/80 ${closeButtonClassName}`}\n aria-label=\"Close popup\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\n\ninterface PopupButtonsProps {\n children: ReactNode;\n alignment?: \"left\" | \"center\" | \"right\";\n className?: string;\n}\n\nexport function PopupButtons({ children, alignment = \"center\", className = \"\" }: PopupButtonsProps) {\n const alignmentClasses = {\n left: \"justify-start\",\n center: \"justify-center\",\n right: \"justify-end\",\n };\n\n return <div className={`flex gap-3 ${alignmentClasses[alignment]} ${className}`}>{children}</div>;\n}\n","\"use client\";\n\nimport { createPortal } from \"react-dom\";\nimport { ReactNode, useEffect, useRef } from \"react\";\nimport { PopupTitle } from \"./PopupTitle\";\nimport { PopupButtons } from \"./PopupButtons\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\nexport interface BasePopupProps {\n title: string;\n children: ReactNode;\n onClose?: () => void;\n type?: \"default\" | \"success\" | \"error\" | \"warning\" | \"info\" | \"spotify\" | \"auth\";\n icon?: LucideIcon;\n isDismissable?: boolean;\n className?: string;\n overlayClassName?: string;\n titleClassName?: string;\n titleTextClassName?: string;\n closeButtonClassName?: string;\n /** Sizes the popup to its content (up to the type's max width) instead of filling it. */\n fitContent?: boolean;\n contentClassName?: string;\n showOkButton?: boolean;\n showCancelButton?: boolean;\n okButtonText?: string;\n okButtonDisabled?: boolean;\n cancelButtonText?: string;\n onOk?: () => void;\n onCancel?: () => void;\n buttonAlignment?: \"left\" | \"center\" | \"right\";\n /**\n * Distance (in px) reserved at the top of the viewport, e.g. for a fixed app header/banner.\n * Each consuming app passes its own value. Defaults to 0.\n */\n topOffset?: number;\n /** Keeps keyboard focus within the popup and restores it to the opener when dismissed. */\n trapFocus?: boolean;\n /** Closes a dismissable popup on Escape. */\n closeOnEscape?: boolean;\n /** Closes a dismissable popup when the backdrop is clicked. */\n closeOnBackdrop?: boolean;\n}\n\nconst typeClasses: Record<string, string> = {\n default: \"w-full max-w-lg\",\n success: \"w-full max-w-lg\",\n error: \"w-full max-w-lg\",\n warning: \"w-full max-w-lg\",\n info: \"w-full max-w-lg\",\n spotify: \"w-full max-w-md\",\n auth: \"w-full max-w-md\",\n};\n\nconst contentBgClasses: Record<string, string> = {\n spotify: \"bg-green-500\",\n auth: \"bg-gray-800\",\n};\n\nexport function BasePopup(props: BasePopupProps) {\n const {\n title,\n children,\n onClose,\n type = \"default\",\n icon,\n isDismissable = true,\n className,\n overlayClassName = \"\",\n titleClassName = \"\",\n titleTextClassName = \"\",\n closeButtonClassName = \"\",\n fitContent = false,\n contentClassName = \"\",\n showOkButton = false,\n showCancelButton = false,\n okButtonText = \"OK\",\n cancelButtonText = \"Cancel\",\n onOk,\n okButtonDisabled = false,\n onCancel,\n buttonAlignment = \"center\",\n topOffset = 0,\n trapFocus = false,\n closeOnEscape = false,\n closeOnBackdrop = false,\n } = props;\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const dialog = dialogRef.current;\n const focusableSelector =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const getFocusable = () =>\n Array.from(dialog?.querySelectorAll<HTMLElement>(focusableSelector) ?? []).filter(\n (element) => !element.hasAttribute(\"hidden\") && element.getAttribute(\"aria-hidden\") !== \"true\",\n );\n\n if (trapFocus) (getFocusable()[0] ?? dialog)?.focus();\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && closeOnEscape && isDismissable) {\n event.preventDefault();\n onClose?.();\n return;\n }\n if (!trapFocus || event.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n event.preventDefault();\n dialog?.focus();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (event.shiftKey && (document.activeElement === first || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (document.activeElement === last || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n first.focus();\n }\n };\n\n if (trapFocus || closeOnEscape) document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n if (trapFocus || closeOnEscape) document.removeEventListener(\"keydown\", handleKeyDown);\n if (trapFocus && previousFocus?.isConnected) previousFocus.focus();\n };\n }, [closeOnEscape, isDismissable, onClose, trapFocus]);\n\n const baseClasses = \"bg-white rounded-lg\";\n\n const renderButtons = () => {\n if (!showOkButton && !showCancelButton) return null;\n\n return (\n <div className=\"mt-4 pt-4 border-t\">\n <PopupButtons alignment={buttonAlignment}>\n {showCancelButton && (\n <Button onClick={onCancel || onClose || (() => {})} variant=\"secondary\">\n {cancelButtonText}\n </Button>\n )}\n {showOkButton && (\n <Button onClick={onOk || onClose || (() => {})} disabled={okButtonDisabled}>\n {okButtonText}\n </Button>\n )}\n </PopupButtons>\n </div>\n );\n };\n\n const popupComponent = (\n <div\n className={`fixed z-50 flex items-center justify-center bg-transparent ${overlayClassName}`}\n style={{\n top: topOffset,\n left: 0,\n right: 0,\n bottom: 0,\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"popup-title\"\n onClick={closeOnBackdrop && isDismissable ? onClose : undefined}\n >\n <div\n ref={dialogRef}\n tabIndex={trapFocus ? -1 : undefined}\n className={`${baseClasses} ${fitContent ? typeClasses[type].replace(\"w-full\", \"w-fit\") : typeClasses[type]} ${className || \"\"}`}\n onClick={(e) => e.stopPropagation()}\n >\n <PopupTitle\n title={title}\n onClose={onClose ?? (() => {})}\n isDismissable={isDismissable}\n icon={icon}\n className={titleClassName}\n titleClassName={titleTextClassName}\n closeButtonClassName={closeButtonClassName}\n />\n <div className={`popup-content rounded-b-lg p-4 ${contentBgClasses[type] ?? \"\"} ${contentClassName}`}>\n {children}\n {renderButtons()}\n </div>\n </div>\n </div>\n );\n\n return createPortal(popupComponent, document.body);\n}\n\nexport default BasePopup;\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport type ToastProps = {\n message: string;\n onClose: () => void;\n durationMs?: number;\n};\n\nexport default function Toast({ message, onClose, durationMs = 2200 }: ToastProps) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n const timeout = window.setTimeout(onClose, durationMs);\n return () => window.clearTimeout(timeout);\n }, [durationMs, onClose]);\n\n if (!mounted) return null;\n\n return createPortal(\n <div className=\"pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4\">\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-body text-[var(--color-text)] shadow-lg ring-1 ring-black/10\"\n >\n {message}\n </div>\n </div>,\n document.body,\n );\n}\n","\"use client\";\n\nimport { MdError, MdCheckCircle, MdUpload } from \"react-icons/md\";\nimport { useTrackUpload, type UploadStatus, type UseTrackUploadOptions } from \"@behindthemusictree/app-kit/popup\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { capitalize, useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\n\ntype TrackUploadPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> &\n UseTrackUploadOptions & {\n onClose?: () => void;\n };\n\nfunction getStatusIcon(status: UploadStatus) {\n switch (status) {\n case \"success\":\n return <MdCheckCircle className=\"text-[var(--color-green-500)]\" size={20} />;\n case \"error\":\n return <MdError className=\"text-[var(--color-red-500)]\" size={20} />;\n case \"uploading\":\n return <MdUpload className=\"text-[var(--color-blue-500)] animate-pulse\" size={20} />;\n default:\n return <div className=\"w-5 h-5 rounded-full border-2 border-[var(--color-neutral-300)]\" />;\n }\n}\n\nfunction getStatusText(status: UploadStatus) {\n switch (status) {\n case \"success\":\n return \"Uploaded\";\n case \"error\":\n return \"Failed\";\n case \"uploading\":\n return \"Uploading...\";\n default:\n return \"Pending\";\n }\n}\n\nexport default function TrackUploadPopup({\n files,\n genre,\n onProcessFile,\n onComplete,\n onClose,\n uploadTimeoutMs,\n ...rest\n}: TrackUploadPopupProps) {\n const { items, isUploading, allComplete, successfulCount, errorCount } = useTrackUpload({\n files,\n genre,\n onProcessFile,\n onComplete,\n uploadTimeoutMs,\n });\n\n const displayTotal = items.length > 0 ? items.length : files.length;\n const trackNoun = useTrackNoun();\n\n return (\n <BasePopup\n {...rest}\n onClose={onClose}\n title={`Upload ${capitalize(trackNoun.plural)} (${successfulCount}/${displayTotal})`}\n isDismissable\n showOkButton\n okButtonText=\"OK\"\n okButtonDisabled={isUploading || !allComplete}\n onOk={onClose}\n >\n <div className=\"space-y-4\">\n {items.map((item) => (\n <div key={item.id} className=\"border rounded-lg p-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"flex items-center space-x-3\">\n {getStatusIcon(item.status)}\n <div>\n <div className=\"font-medium text-body truncate max-w-xs\" title={item.file.name}>\n {item.file.name}\n </div>\n <div className=\"text-caption text-[var(--color-neutral-500)]\">{(item.file.size / 1024 / 1024).toFixed(1)} MB</div>\n </div>\n </div>\n <div className=\"text-body text-[var(--color-neutral-600)]\">{getStatusText(item.status)}</div>\n </div>\n\n {item.status === \"uploading\" && (\n <div className=\"w-full bg-[var(--color-neutral-200)] rounded-full h-2\">\n <div\n className=\"bg-[var(--color-blue-500)] h-2 rounded-full transition-all duration-300\"\n style={{ width: `${item.progress}%` }}\n />\n </div>\n )}\n\n {item.status === \"error\" && item.error && (\n <div className=\"text-[var(--color-red-500)] text-body mt-2\">\n {item.error.name === \"InvalidInputError\"\n ? \"Upload failed due to invalid file data. Please check your file and try again.\"\n : item.error.name === \"ZodError\"\n ? \"Upload failed due to a server error. Please try again later.\"\n : item.error.message}\n </div>\n )}\n </div>\n ))}\n\n {allComplete && (\n <div className=\"flex justify-between items-center\">\n <div className=\"text-body text-[var(--color-neutral-600)]\">\n {successfulCount} successful, {errorCount} failed\n </div>\n </div>\n )}\n </div>\n </BasePopup>\n );\n}\n","\"use client\";\n\nimport { AlertCircle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\n\ntype AuthErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n message: string;\n onClose: () => void;\n};\n\nexport default function AuthErrorPopup({ message, onClose, ...rest }: AuthErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Sign-in error\"\n isDismissable\n icon={AlertCircle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <p className=\"text-center text-lg font-medium text-[var(--color-text)]\">{message}</p>\n <Button onClick={onClose} variant=\"secondary\" className=\"w-full max-w-xs\">\n Close\n </Button>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { AlertTriangle, AlertCircle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { ErrorCode } from \"@behindthemusictree/app-kit/transport\";\n\ntype InternalErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n errorCode: ErrorCode;\n /**\n * Support contact email shown in the \"if the problem persists\" message. Passed by the\n * consuming app (from whatever env var / config it uses) so this package doesn't assume a\n * specific env var name.\n */\n contactEmail?: string | null;\n};\n\nexport default function InternalErrorPopup({ errorCode, contactEmail, ...rest }: InternalErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Internal Error\"\n isDismissable={false}\n icon={AlertTriangle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <AlertCircle className=\"h-16 w-16 text-[var(--color-red-500)]\" strokeWidth={1.5} />\n <div>\n <p className=\"text-center text-[var(--color-neutral-600)]\">\n Please try again. If the problem persists, contact us at{\" \"}\n <a href={`mailto:${contactEmail}`} className=\"text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]\">\n {contactEmail}\n </a>\n </p>\n </div>\n {errorCode && (\n <div className=\"text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]\">\n Error Code: {errorCode}\n </div>\n )}\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { AlertTriangle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { ErrorCode } from \"@behindthemusictree/app-kit/transport\";\n\ntype NetworkErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n errorCode: ErrorCode;\n};\n\nconst OFFLINE_MESSAGE = \"It seems that you are not connected to the internet. Please check your connection and try again.\";\nconst UNREACHABLE_MESSAGE = \"We couldn't reach the server. Please try again in a moment.\";\n\nexport default function NetworkErrorPopup({ errorCode, ...rest }: NetworkErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Network Error\"\n isDismissable={false}\n icon={AlertTriangle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <AlertTriangle className=\"h-16 w-16 text-[var(--color-neutral-600)]\" strokeWidth={1.5} />\n <p className=\"text-center text-[var(--color-neutral-700)]\">\n {errorCode === ErrorCode.NETWORK_OFFLINE ? OFFLINE_MESSAGE : UNREACHABLE_MESSAGE}\n </p>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\nimport { User } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { FaSpotify } from \"react-icons/fa\";\nimport { FcGoogle } from \"react-icons/fc\";\n\ntype AuthPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n handleSpotifyOAuth: (redirectAfterAuthPath?: string) => void;\n handleGoogleOAuth?: (redirectAfterAuthPath?: string) => void;\n redirectAfterAuthPath?: string;\n spotifyOnly?: boolean;\n message?: string;\n /**\n * Body copy shown when `spotifyOnly` is true. Wording (app name, feature description) is\n * app-specific, so each consuming app supplies its own instead of this package assuming one.\n */\n spotifyOnlyDescription: ReactNode;\n /** Body copy shown when `spotifyOnly` is false, for the same reason as `spotifyOnlyDescription`. */\n defaultDescription: ReactNode;\n};\n\nexport default function AuthPopup({\n handleSpotifyOAuth,\n handleGoogleOAuth,\n redirectAfterAuthPath,\n spotifyOnly,\n message,\n spotifyOnlyDescription,\n defaultDescription,\n ...rest\n}: AuthPopupProps) {\n const showGoogle = !spotifyOnly && handleGoogleOAuth;\n\n return (\n <BasePopup\n {...rest}\n title={spotifyOnly ? \"Connect with Spotify\" : \"Sign in\"}\n isDismissable={false}\n icon={User}\n type=\"auth\"\n children={\n <div className=\"flex flex-col items-center space-y-7\">\n <div className=\"px-2 text-center\">\n {message && <p className=\"mb-3 text-base font-medium leading-relaxed text-amber-200\">{message}</p>}\n <p className=\"text-lg font-medium leading-relaxed text-white\">\n {spotifyOnly ? spotifyOnlyDescription : defaultDescription}\n </p>\n </div>\n <div className=\"flex w-full flex-col items-center gap-3\">\n <Button\n onClick={() => handleSpotifyOAuth(redirectAfterAuthPath)}\n className=\"relative mb-2 w-fit transform bg-green-600 px-8 py-3 text-white shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-green-700 hover:shadow-xl\"\n >\n <span className=\"flex items-center justify-center\">\n <FaSpotify className=\"absolute left-6 text-3xl\" />\n <span className=\"w-full pl-14 pr-8 text-center text-lg font-medium\">Sign in with Spotify</span>\n </span>\n </Button>\n {showGoogle && (\n <Button\n variant=\"outline\"\n onClick={() => handleGoogleOAuth!(redirectAfterAuthPath)}\n className=\"relative w-fit transform border-white bg-white px-8 py-3 text-black shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-[var(--color-neutral-100)] hover:shadow-xl\"\n >\n <span className=\"flex items-center justify-center\">\n <FcGoogle className=\"absolute left-6 text-2xl\" />\n <span className=\"w-full pl-14 pr-8 text-center text-lg font-medium text-black\">\n Sign in with Google\n </span>\n </span>\n </Button>\n )}\n </div>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { FaSpotify } from \"react-icons/fa\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { User } from \"lucide-react\";\nimport { getSpotifyAllowlistMailtoHref } from \"@behindthemusictree/app-kit/transport\";\n\ntype SpotifyAuthErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n message: string;\n details?: string;\n onClose: () => void;\n /**\n * Support contact email used to build the allowlist-request mailto link. Passed by the\n * consuming app (from whatever env var / config it uses) so this package doesn't assume a\n * specific env var name.\n */\n contactEmail?: string | null;\n};\n\nexport default function SpotifyAuthErrorPopup({\n message,\n details,\n onClose,\n contactEmail = null,\n ...rest\n}: SpotifyAuthErrorPopupProps) {\n const requestAccessHref = getSpotifyAllowlistMailtoHref(contactEmail);\n\n return (\n <BasePopup\n {...rest}\n title=\"Authentication Failed\"\n isDismissable\n icon={User}\n children={\n <div className=\"flex flex-col items-center space-y-8 py-4\">\n <FaSpotify className=\"text-[#1DB954] text-7xl\" />\n <div className=\"space-y-3 text-center\">\n <p className=\"text-xl font-medium text-[var(--color-text)]\">{message}</p>\n {details && (\n <p className=\"text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]\">{details}</p>\n )}\n <div className=\"space-y-2 text-center\">\n <p className=\"text-base text-[var(--color-neutral-700)]\">\n The Spotify app is in development mode, so only allowlisted accounts can connect.\n </p>\n {requestAccessHref && contactEmail ? (\n <p className=\"text-base text-[var(--color-neutral-700)]\">\n Request access by emailing your{\" \"}\n <a\n href={requestAccessHref}\n className=\"text-[#1DB954] font-medium underline hover:no-underline focus:outline-none focus:ring-2 focus:ring-[#1DB954] focus:ring-offset-1 rounded\"\n >\n Spotify full name and Spotify email address\n </a>{\" \"}\n to{\" \"}\n <a\n href={requestAccessHref}\n className=\"text-[#1DB954] font-medium underline hover:no-underline focus:outline-none focus:ring-2 focus:ring-[#1DB954] focus:ring-offset-1 rounded\"\n >\n {contactEmail}\n </a>\n .\n </p>\n ) : (\n <p className=\"text-base text-[var(--color-neutral-700)]\">To request access, contact the app owner.</p>\n )}\n </div>\n </div>\n <Button\n onClick={onClose}\n className=\"bg-[#1DB954] hover:bg-[#1DB954]/90 text-white w-full max-w-xs transform transition-all duration-200 hover:scale-[1.02] shadow-lg hover:shadow-xl\"\n >\n <FaSpotify className=\"mr-2 text-lg\" />\n Try Again\n </Button>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\nimport { useAuthCallback, type AuthCallbackState, type UseAuthCallbackOptions } from \"@behindthemusictree/app-kit/auth\";\n\nexport interface AuthCallbackHandlerProps extends UseAuthCallbackOptions {\n /** Optional custom \"connecting…\" / error UI; defaults to a minimal full-screen overlay. */\n renderStatus?: (state: Exclude<AuthCallbackState, { status: null }>) => ReactNode;\n}\n\n/** Handles OAuth callbacks at layout level. Rendered in the app shell so it runs on every load. */\nexport default function AuthCallbackHandler({ renderStatus, ...options }: AuthCallbackHandlerProps) {\n const state = useAuthCallback(options);\n\n if (state.status === null) return null;\n\n if (renderStatus) return <>{renderStatus(state)}</>;\n\n if (state.status === \"error\") {\n return (\n <div className=\"fixed inset-0 z-[100] flex flex-col items-center justify-center bg-[var(--color-neutral-100)] p-4\">\n <div className=\"w-full max-w-md rounded-lg border border-[color-mix(in_srgb,var(--color-red-500)_20%,transparent)] bg-[color-mix(in_srgb,var(--color-red-500)_10%,transparent)] p-4\">\n <h2 className=\"mb-2 font-semibold text-[var(--color-red-500)]\">Authentication Error</h2>\n <p className=\"text-[color-mix(in_srgb,var(--color-red-500)_80%,transparent)]\">{state.message}</p>\n <button\n type=\"button\"\n onClick={state.goHome}\n className=\"mt-4 rounded bg-[var(--color-red-600)] px-4 py-2 text-white hover:bg-[var(--color-red-700)]\"\n >\n Go to home\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"fixed inset-0 z-[100] flex flex-col items-center justify-center bg-[var(--color-neutral-100)]\" data-page=\"auth-callback-handler\">\n <div className=\"text-center\">\n <h1 className=\"mb-4 text-2xl font-bold\">Connecting…</h1>\n <p className=\"text-[var(--color-neutral-600)]\">Completing sign-in.</p>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState, type ComponentProps, type ComponentType, type ReactNode } from \"react\";\nimport { useIsMutating } from \"@tanstack/react-query\";\nimport { z } from \"zod\";\nimport { Plus } from \"lucide-react\";\nimport { Maximize2, Minimize2 } from \"lucide-react\";\nimport { IconTextButton, IconButton, Button, SegmentedControl, DetailPanel, useObscuredInset } from \"@behindthemusictree/ui\";\n\nimport {\n GenreTreeWheelSkeleton,\n GenreTreeViewSkeleton,\n useGenreNodeRelations,\n} from \"@behindthemusictree/genre-tree-view\";\nimport type {\n GenreTreeAction,\n GenreTreeNode,\n GenreTreeViewMode,\n GenreTreeViewport,\n GenreTreeProps,\n GenreNodeStyleResolver,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport {\n CriteriaMinimum,\n CriteriaPlaylistSimple,\n toGenreUuid,\n type GenreUuid,\n type ArtistSearchResult,\n type RenderSongLink,\n type SongSearchResult,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaOverview } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useGenreTreeViewState, useArtist, useUpdateGenre, genreUpdateMutationKey } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport type { GenreDetailSlots } from \"./GenreDetailExtras\";\nimport type { GenrePlaylistTracksSlots } from \"./GenrePlaylistTracks\";\nimport type { HostOverlayPanel } from \"./overlayPanel\";\nimport { toTreeNodes } from \"./playlist-tree/toTreeNodes\";\nimport { toGenreNodeStyles } from \"./playlist-tree/toGenreNodeStyles\";\nimport type { RenderArtistLink, RenderPlaceLink } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport GenrePlaylistTreePerRoot from \"./playlist-tree/TreePerRoot\";\nimport GenrePlaylistTreeWheel from \"./playlist-tree/TreeWheel\";\nimport GenrePlaylistTreeWheelRadialPopCore, { type GenreFocusProps } from \"./playlist-tree/TreeWheelRadialPopCore\";\nimport { GenreTreeWheelHandoff } from \"./GenreTreeWheelHandoff\";\nimport { GenreTreeSearch, type GenreSearchGroupsProps } from \"./GenreTreeSearch\";\nimport { type SearchGroup } from \"./search\";\nimport { useGenreDetailContent } from \"./GenreDetailPanel\";\nimport ChangeParentPopup, { type ParentChange } from \"./ChangeParentPopup\";\nimport { useEntityPanel } from \"./useEntityPanel\";\nimport { SizeMetricToggle } from \"./SizeMetricToggle\";\nimport { hasViewsCount, type GenreTreeSizeMetric } from \"./playlist-tree/size-metric\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\nimport type { GetGenreTreeShareUrl, GenreTreeShareTarget } from \"./share\";\n\nexport type {\n FocusChangeReason,\n GenreTreeViewMode,\n} from \"@behindthemusictree/genre-tree-view\";\nexport type { GenreFocusProps } from \"./playlist-tree/TreeWheelRadialPopCore\";\n\n/** Artists are searched by default; picking one opens its panel (see `artistUuid`). */\nexport type ArtistSearchProps =\n | { artistSearch: false; onArtistSelect?: never; artistSearchBaseUrl?: never }\n | {\n artistSearch?: true;\n /** Notified when a suggestion is picked, after the view opens its artist panel. */\n onArtistSelect?: (artist: ArtistSearchResult) => void;\n /** Backend that serves `artists/` (search and the artist panel). Defaults to `getBackendBaseUrl`. */\n artistSearchBaseUrl?: () => string;\n };\n\nconst NO_POP_ROOT_TITLE = \"This genre tree has no 'Mainstream Pop' root yet\";\n\nexport type GenreTreeViewProps<O extends CriteriaOverview = CriteriaOverview> = {\n scope: Scope;\n /** \"regions\" lays the info panel out in the brand's left/center/right columns (see brand `--layout-center-*`). */\n placement?: \"default\" | \"regions\";\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n getBackendBaseUrl: () => string;\n /** Called after the Parent popup moved a genre; `from` and `to` are genre (criteria) uuids, `from` null for a root genre. */\n onParentChanged?: (change: ParentChange) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n /** Controlled view mode. When provided, the internal Stacked/Wheel toggle is not rendered — the consumer owns that UI. */\n viewMode?: GenreTreeViewMode;\n /**\n * Selected genre entity, including genres outside the rendered tree. A raw URL value is accepted as is:\n * one that names no genre opens a \"not found\" panel.\n */\n selectedGenreUuid?: string | null;\n /** Called on every user-driven selection change (tree click, search pick, search clear). */\n onSelectedGenreUuidChange?: (genreUuid: GenreUuid | null) => void;\n /** Mount-only seed for the pan/zoom (wheel, pop-core and stacked views), replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Restore silently after layout; use a new revision for each navigation. Supply focus, selection,\n * and restoration together. User interaction supersedes a pending request. In stacked view,\n * the selected genre must resolve to a root; outline ignores restoration. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. In stacked view, only the tree holding the selection reports. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** When true, hides the \"Add root\" button and suppresses per-node\n * create/rename affordances, for a read-only consumer. Defaults to false. */\n readOnly?: boolean;\n /** Further result groups (e.g. places) shown in the search box next to genres, artists and songs. */\n extraSearchGroups?: SearchGroup[];\n /** Host search hooks run inside this subtree, so typing does not rerender the tree page. */\n SearchGroups?: ComponentType<GenreSearchGroupsProps>;\n /** Fires with the typed search text (empty when cleared), so a host can drive its own `extraSearchGroups`. */\n onSearchQueryChange?: (text: string) => void;\n /** Fires when the search box gains focus, e.g. to load data for `extraSearchGroups` lazily. */\n onSearchFocus?: () => void;\n /** Root element classes; the component adds no outer margin. */\n className?: string;\n /** Shows the \"Tree display options\" group (e.g. Rotation). Defaults to true. */\n showDisplayOptions?: boolean;\n /** Shows the \"Add root\" button (still hidden when `readOnly`). Defaults to true; a host rendering its own passes false. */\n showAddRoot?: boolean;\n /** Controlled wheel rotation. When provided, the internal Rotation toggle is not rendered — the consumer owns that UI. */\n allowWheelRotation?: boolean;\n /** Parses the selected genre's overview; pass an extended schema to keep consumer-specific fields. */\n criteriaOverviewSchema?: z.ZodType<O, unknown>;\n /** Consumer-specific rows rendered in the info panel after Summary. */\n renderGenreDetailExtras?: (overview: O) => ReactNode;\n /** Host control displayed before the size metric in the floating controls. */\n floatingControlsLeading?: ReactNode;\n /** Controlled size metric of the wheel and pop-core nodes: song count or summed song views. Uncontrolled when omitted\n * (starts on songs). The toggle is hidden while an artist filters the tree, which only has song counts. */\n sizeMetric?: GenreTreeSizeMetric;\n onSizeMetricChange?: (metric: GenreTreeSizeMetric) => void;\n /** When set, artist names in the info panel's track list render through it (e.g. a router `Link`). In the artist\n * panel, names otherwise render as buttons that switch the panel to that artist. */\n renderArtistLink?: RenderArtistLink;\n /** Controlled artist panel (an artist uuid). It shares the info panel's slot: opening an artist clears the selected\n * genre; selecting a genre keeps the artist as a filter (the tree shows only genres the artist has songs in, and\n * the genre's songs and play button are limited to the artist) and shows the genre's panel instead. A host\n * `overlayPanel` takes precedence over the artist panel. */\n artistUuid?: string | null;\n /** Called when the user opens an artist (search pick, member link) or closes its panel. */\n onArtistUuidChange?: (uuid: string | null) => void;\n /** Controlled expanded state of the artist panel. Uncontrolled, it resets to compact on each artist. */\n artistExpanded?: boolean;\n onArtistExpandedChange?: (expanded: boolean) => void;\n /** Controlled song panel (a song uuid). Like the artist panel it shares the info panel's slot: opening a song clears\n * the selected genre and the artist; selecting a genre closes it. A host `overlayPanel` takes precedence. */\n songUuid?: string | null;\n /** Called when the user opens a song (search pick, title link) or closes its panel. */\n onSongUuidChange?: (uuid: string | null) => void;\n /** Controlled expanded state of the song panel. Uncontrolled, it resets to compact on each song. */\n songExpanded?: boolean;\n onSongExpandedChange?: (expanded: boolean) => void;\n /** Songs are searched by default; picking one opens its panel. */\n songSearch?: boolean;\n onSongSelect?: (song: SongSearchResult) => void;\n /** When set, song titles in the info panel's track list render through it (e.g. a router `Link` to the song).\n * By default they are buttons that open the song panel. */\n renderSongLink?: RenderSongLink;\n /** When set, the artist panel renders the artist's origin through it (e.g. a router `Link` to the map region). */\n renderPlaceLink?: RenderPlaceLink;\n /** Resolves a selected genre, artist or song to a share URL using the host app's routes. */\n getShareUrl?: GetGenreTreeShareUrl;\n} & ArtistSearchProps &\n GenreDetailSlots<O> &\n GenrePlaylistTracksSlots &\n GenreFocusProps & {\n /** Appended to a selected genre's panel, e.g. destructive actions. */\n renderDangerZone?: (node: GenreTreeNode) => ReactNode;\n /** Controlled expanded state of the genre panel. Uncontrolled when omitted. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** A host panel rendered in the detail panel's slot; it takes precedence over the genre, song and artist panels.\n * Like theirs, its title fills the search field, whose clear button closes it. */\n overlayPanel?: HostOverlayPanel;\n /** Hides the info panel behind its edge tab; uncontrolled when omitted. Only applies with `placement=\"regions\"`. */\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n };\n\nconst REGIONS_CLASS =\n \"[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]\";\n\nconst noop = () => {};\n\nexport function GenreTreeView<O extends CriteriaOverview = CriteriaOverview>({\n scope,\n handleGenreCreationAction,\n handleGenreRenameAction,\n onParentChanged,\n getBackendBaseUrl,\n additionalActions,\n viewMode: controlledViewMode,\n selectedGenreUuid: controlledSelectedGenreUuid,\n onSelectedGenreUuidChange,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n readOnly = false,\n className,\n showDisplayOptions = true,\n showAddRoot = true,\n allowWheelRotation: controlledAllowWheelRotation,\n criteriaOverviewSchema,\n renderGenreDetailExtras,\n floatingControlsLeading,\n sizeMetric: controlledSizeMetric,\n onSizeMetricChange,\n renderArtistLink,\n artistUuid: controlledArtistUuid,\n onArtistUuidChange,\n artistExpanded: controlledArtistExpanded,\n onArtistExpandedChange,\n getShareUrl,\n extraSearchGroups = [],\n SearchGroups,\n onSearchQueryChange,\n onSearchFocus,\n artistSearch = true,\n onArtistSelect,\n artistSearchBaseUrl,\n songUuid: controlledSongUuid,\n onSongUuidChange,\n songExpanded: controlledSongExpanded,\n onSongExpandedChange,\n songSearch = true,\n onSongSelect,\n renderSongLink,\n renderPlaceLink,\n renderSummary,\n renderEssentialTracks,\n renderSongLeading,\n renderSongActions,\n renderTracksToolbar,\n renderDangerZone,\n expanded,\n onExpandedChange,\n collapsed,\n onCollapsedChange,\n overlayPanel,\n placement = \"default\",\n ...focus\n}: GenreTreeViewProps<O>) {\n const getShareUrlRef = useRef(getShareUrl);\n getShareUrlRef.current = getShareUrl;\n const [internalArtistUuid, setInternalArtistUuid] = useState<string | null>(null);\n const isArtistControlled = controlledArtistUuid !== undefined;\n const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;\n const [internalSongUuid, setInternalSongUuid] = useState<string | null>(null);\n const isSongControlled = controlledSongUuid !== undefined;\n const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;\n const changeSong = (uuid: string | null) => {\n if (!isSongControlled) setInternalSongUuid(uuid);\n onSongUuidChange?.(uuid);\n };\n const [internalSizeMetric, setInternalSizeMetric] = useState<GenreTreeSizeMetric>(\"songs\");\n const sizeMetric = controlledSizeMetric ?? internalSizeMetric;\n const deferredSizeMetric = useDeferredValue(sizeMetric);\n const changeSizeMetric = (metric: GenreTreeSizeMetric) => {\n if (controlledSizeMetric === undefined) setInternalSizeMetric(metric);\n onSizeMetricChange?.(metric);\n };\n const changeArtist = (uuid: string | null) => {\n if (!isArtistControlled) setInternalArtistUuid(uuid);\n onArtistUuidChange?.(uuid);\n };\n const {\n isLoading,\n isError,\n refetch,\n isFetching: isTreeFetching,\n genrePlaylistByNodeId,\n visibleGenrePlaylists,\n focusUuids,\n groupedGenrePlaylistsByRoot,\n selectedGenreUuid,\n selectGenre,\n selectedNodeId,\n selectedGenrePlaylist,\n selectNode,\n selectGenrePlaylist,\n clearSelection,\n viewMode,\n isViewModeControlled: isControlled,\n setViewMode,\n canShowPopCore,\n allowWheelRotation: internalAllowWheelRotation,\n toggleWheelRotation,\n onNodeHover: handleNodeHover,\n } = useGenreTreeViewState<O>({\n scope,\n getBackendBaseUrl,\n viewMode: controlledViewMode,\n selectedGenreUuid: controlledSelectedGenreUuid,\n onSelectedGenreUuidChange,\n criteriaOverviewSchema,\n artistUuid,\n });\n\n // Renderer revision tracking is per instance: bind a navigation to one stacked root so a\n // later user selection cannot replay the same request in another renderer.\n const restoreRevision = viewportRestore?.revision;\n const [stackedRestoreOwner, setStackedRestoreOwner] = useState<{\n revision: string | number | undefined;\n rootUuid: string | undefined;\n }>({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });\n let restoreRootUuid = stackedRestoreOwner.rootUuid;\n if (stackedRestoreOwner.revision !== restoreRevision) {\n restoreRootUuid = selectedGenrePlaylist?.root.uuid;\n setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });\n } else if (restoreRootUuid === undefined && selectedGenrePlaylist) {\n restoreRootUuid = selectedGenrePlaylist.root.uuid;\n setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });\n }\n\n const isGenreUpdating = useIsMutating({ mutationKey: genreUpdateMutationKey }) > 0;\n const { mutate: updateGenre } = useUpdateGenre(scope, getBackendBaseUrl);\n const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;\n // The artist detail can load after the filtered counts, so use the UUID as the filter state.\n const isArtistFiltered = artistUuid !== null;\n const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);\n\n const artistResult = useArtist(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);\n const filterArtistName = artistResult.status === \"success\" ? artistResult.artist.name : null;\n const filterArtist = useMemo(\n () => (artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null),\n [artistUuid, filterArtistName],\n );\n const hasSelectedGenreNode =\n selectedGenrePlaylist !== undefined && visibleGenrePlaylists.some(({ uuid }) => uuid === selectedGenrePlaylist.uuid);\n const playback = useGenrePlaylistPlayback({ scope, genrePlaylists: visibleGenrePlaylists, artist: filterArtist });\n const openArtist = (uuid: string) => {\n if (selectedGenreUuid !== null) clearSelection();\n if (songUuid !== null) changeSong(null);\n changeArtist(uuid);\n };\n const openSong = (uuid: string) => {\n if (selectedGenreUuid !== null) clearSelection();\n changeSong(uuid);\n };\n // Kept stable: it feeds the memoized info panel body, which must not rebuild on every render.\n const openSongRef = useRef(openSong);\n openSongRef.current = openSong;\n const resolvedRenderSongLink = useCallback<RenderSongLink>(\n (song) =>\n renderSongLink ? (\n renderSongLink(song)\n ) : (\n <button type=\"button\" onClick={() => openSongRef.current(song.uuid)} className=\"hover:underline\">\n {song.title}\n </button>\n ),\n [renderSongLink],\n );\n const [expandedSongUuid, setExpandedSongUuid] = useState<string | null>(null);\n // Keyed by artist, so switching artists (including a host's back/forward) starts compact.\n const [expandedArtistUuid, setExpandedArtistUuid] = useState<string | null>(null);\n const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;\n const songBaseUrl = getBackendBaseUrl;\n const resolvedRenderArtistLink: RenderArtistLink =\n renderArtistLink ??\n ((artist) =>\n artist.isSpecialPurpose ? (\n artist.name\n ) : (\n <button type=\"button\" onClick={() => openArtist(artist.uuid)} className=\"hover:underline\">\n {artist.name}\n </button>\n ));\n const getGenrePath = (genre: CriteriaMinimum): CriteriaPlaylistSimple[] => {\n const path: CriteriaPlaylistSimple[] = [];\n let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);\n while (current) {\n path.unshift(current);\n const parentUuid: string | undefined = current.parent?.uuid;\n current = parentUuid ? visibleGenrePlaylists.find((playlist) => playlist.uuid === parentUuid) : undefined;\n }\n return path;\n };\n const entityPanel = useEntityPanel({\n scope,\n getBackendBaseUrl: songBaseUrl,\n getArtistBackendBaseUrl: artistBaseUrl,\n getShareUrl: getShareUrlRef.current,\n renderArtistLink: resolvedRenderArtistLink,\n renderSongLink: resolvedRenderSongLink,\n renderPlaceLink,\n song: {\n uuid: songUuid,\n expanded: controlledSongExpanded ?? (songUuid !== null && expandedSongUuid === songUuid),\n onExpandedChange: (on) => {\n if (controlledSongExpanded === undefined) setExpandedSongUuid(on ? songUuid : null);\n onSongExpandedChange?.(on);\n },\n onClose: () => changeSong(null),\n },\n artist: {\n uuid: artistUuid,\n expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),\n onExpandedChange: (on) => {\n if (controlledArtistExpanded === undefined) setExpandedArtistUuid(on ? artistUuid : null);\n onArtistExpandedChange?.(on);\n },\n onClose: () => changeArtist(null),\n },\n getGenrePath,\n onSelectGenrePlaylist: (genrePlaylist) => {\n changeSong(null);\n selectGenrePlaylist(genrePlaylist);\n },\n });\n // A host panel takes precedence over the genre's; a selected genre's panel replaces the artist's or song's, and the\n // artist stays active as a filter.\n const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? undefined : entityPanel);\n\n const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(false);\n const [uncontrolledExpanded, setUncontrolledExpanded] = useState(false);\n const isCollapsed = collapsed ?? uncontrolledCollapsed;\n const isExpanded = expanded ?? uncontrolledExpanded;\n const changeCollapsed = (next: boolean) => {\n setUncontrolledCollapsed(next);\n onCollapsedChange?.(next);\n };\n const changeExpanded = (next: boolean) => {\n setUncontrolledExpanded(next);\n onExpandedChange?.(next);\n };\n useEffect(() => {\n setUncontrolledCollapsed(false);\n }, [selectedGenreUuid, artistUuid, songUuid]);\n\n const [isWheelRevealed, setIsWheelRevealed] = useState(false);\n const usesHandoff = viewMode === \"wheel\" || viewMode === \"pop-core\";\n // The panel stands beside a tree that fades in, so it waits for the tree.\n const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);\n\n // The tree publishes how it draws each node; the panel header and family chips reuse it.\n const [resolveStyle, setResolveStyle] = useState<GenreNodeStyleResolver | null>(null);\n const handleNodeStyleResolverChange = useCallback(\n (resolver: GenreNodeStyleResolver) => setResolveStyle(() => resolver),\n [],\n );\n const panelRef = useRef<HTMLDivElement>(null);\n const obscuredInset = useObscuredInset(panelRef);\n const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };\n\n const nodeMetric: GenreTreeSizeMetric = isArtistFiltered || !canSizeByViews ? \"songs\" : deferredSizeMetric;\n const treeNodes = useMemo(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);\n const relations = useGenreNodeRelations(\n treeNodes,\n !overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,\n resolveStyle,\n );\n\n const treeStyles = useMemo(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);\n\n const validSelectedGenreUuid = toGenreUuid(selectedGenreUuid);\n const [selectionHistory, setSelectionHistory] = useState<{ current: GenreUuid | null; previous: GenreUuid | null }>({ current: validSelectedGenreUuid, previous: null });\n if (selectionHistory.current !== validSelectedGenreUuid) {\n setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });\n }\n const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : undefined;\n\n const { showPopup, hidePopup } = usePopup();\n const reopenPanel = () => { setUncontrolledCollapsed(false); onCollapsedChange?.(false); };\n const handleSelectedNodeChange = (node: { id: string } | null) => {\n reopenPanel();\n if (node !== null && songUuid !== null) changeSong(null);\n selectNode(node);\n };\n const handleGenreSearchSelect = (genrePlaylist: CriteriaPlaylistSimple) => {\n reopenPanel();\n if (songUuid !== null) changeSong(null);\n selectGenrePlaylist(genrePlaylist);\n };\n\n // Mirrors genre-tree-view's isZoomableNode: a node zooms when it has children and at most one pop-side child.\n const selectedUuid = selectedGenrePlaylist?.uuid;\n const selectedChildren = selectedUuid\n ? visibleGenrePlaylists.filter((genrePlaylist) => genrePlaylist.parent?.uuid === selectedUuid)\n : [];\n const canZoomIn =\n viewMode === \"pop-core\" &&\n focus.onFocusGenreChange !== undefined &&\n selectedUuid !== undefined &&\n focus.focusGenreUuid !== selectedUuid &&\n selectedChildren.length > 0 &&\n selectedChildren.filter((child) => child.criteria?.side === \"pop\").length <= 1;\n const handleGenreSearchZoomIn = () => {\n if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, \"zoom-in\");\n };\n const zoomInRef = useRef<(() => void) | undefined>(undefined);\n zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : undefined;\n\n const genrePlaylist = selectedGenrePlaylist;\n const criteria = genrePlaylist?.criteria;\n const parentPlaylist = visibleGenrePlaylists.find(({ uuid }) => uuid === genrePlaylist?.parent?.uuid);\n const canToggleSide = !readOnly && criteria !== undefined && criteria !== null && parentPlaylist !== undefined && parentPlaylist.parent === null;\n const side = criteria?.side ?? \"core\";\n const popSibling = canToggleSide && side === \"core\" ? visibleGenrePlaylists.find((sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist?.uuid && sibling.criteria?.side === \"pop\") : undefined;\n const shareTarget: GenreTreeShareTarget | undefined = validSelectedGenreUuid ? { kind: \"genre\", genreUuid: validSelectedGenreUuid, name: criteria?.name ?? \"Genre\", scope, artistUuid } : undefined;\n const shareUrl = shareTarget ? getShareUrlRef.current?.(shareTarget) ?? undefined : undefined;\n const genreContent = useGenreDetailContent<O>({\n genreUuid: selectedGenreUuid,\n scope, getBackendBaseUrl,\n onSelectGenre: (uuid) => { reopenPanel(); selectGenre(uuid); },\n expanded: isExpanded,\n treeStyles,\n playback,\n genrePlaylist: selectedGenrePlaylist,\n band: {\n ...(relations ? { node: relations.node } : {}),\n shareTarget: shareUrl ? shareTarget : undefined, shareUrl,\n onZoomIn: zoomInRef.current,\n onAddChild: readOnly || !criteria ? undefined : () => handleGenreCreationAction(criteria),\n onRename: readOnly || !criteria ? undefined : () => handleGenreRenameAction(criteria),\n onChangeParent: readOnly || !genrePlaylist || !criteria\n ? undefined\n : () =>\n showPopup(\n <ChangeParentPopup\n genrePlaylist={{ ...genrePlaylist, criteria }}\n genrePlaylists={visibleGenrePlaylists}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n onClose={hidePopup}\n onParentChanged={onParentChanged}\n />,\n ),\n side,\n onToggleSide: canToggleSide && criteria\n ? () => updateGenre({ uuid: criteria.uuid, data: { side: side === \"pop\" ? \"core\" : \"pop\" } })\n : undefined,\n toggleSideDisabledReason: popSibling\n ? `${popSibling.name} is already the pop side of ${parentPlaylist?.name}`\n : undefined,\n additionalActions,\n },\n extras: { criteriaOverviewSchema, renderGenreDetailExtras, renderArtistLink,\n renderSongLink: resolvedRenderSongLink, artist: filterArtist, renderSummary,\n renderEssentialTracks, renderSongLeading, renderSongActions, renderTracksToolbar },\n trailing: relations ? renderDangerZone?.(relations.node) : undefined,\n });\n\n const isRotationControlled = controlledAllowWheelRotation !== undefined;\n const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;\n\n type ActivePanel = {\n title: ReactNode;\n content: ReactNode;\n aside?: ReactNode;\n expanded: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n onClose: () => void;\n // Every panel's name lives in the search field, and the search field closes it; null leaves the field empty.\n searchName: string | null;\n headerAccent?: { background: string; color: string };\n };\n let activePanel: ActivePanel | null = null;\n if (otherPanel) {\n activePanel = {\n title: otherPanel.title,\n content: otherPanel.content,\n aside: otherPanel.extraContent,\n expanded: otherPanel.expanded ?? false,\n onExpandedChange: otherPanel.onExpandedChange,\n onClose: otherPanel.onClose,\n searchName: otherPanel.title,\n };\n } else if (selectedGenreUuid !== null) {\n activePanel = {\n title: genreContent.title,\n content: genreContent.content,\n aside: genreContent.aside,\n expanded: isExpanded,\n onExpandedChange: changeExpanded,\n onClose: clearSelection,\n searchName: genreContent.name,\n headerAccent: genreContent.headerAccent,\n };\n }\n const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);\n\n const detailTab =\n placement === \"regions\" && activePanel?.onExpandedChange\n ? {\n edge: activePanel.expanded\n ? { label: \"Shrink panel\", onClick: () => activePanel.onExpandedChange?.(false) }\n : isCollapsed\n ? null\n : { label: \"Hide panel\", onClick: () => changeCollapsed(true) },\n center: activePanel.expanded\n ? null\n : isCollapsed\n ? { label: \"Show panel\", onClick: () => changeCollapsed(false) }\n : activePanel.onExpandedChange\n ? { label: \"Extend panel\", onClick: () => activePanel.onExpandedChange?.(true) }\n : null,\n }\n : undefined;\n\n const expandButton =\n placement === \"default\" && activePanel?.onExpandedChange ? (\n <IconButton\n aria-label={activePanel.expanded ? \"Shrink panel\" : \"Extend panel\"}\n style={activePanel.headerAccent && { color: \"inherit\" }}\n onClick={() => activePanel.onExpandedChange?.(!activePanel.expanded)}\n >\n {activePanel.expanded ? (\n <Minimize2 aria-hidden=\"true\" className=\"h-4 w-4\" />\n ) : (\n <Maximize2 aria-hidden=\"true\" className=\"h-4 w-4\" />\n )}\n </IconButton>\n ) : null;\n\n const renderArtistFilter = () => {\n if (isLoading || !filterArtist) return null;\n return (\n <span className=\"inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body\">\n <button\n type=\"button\"\n className=\"py-1 pl-3 pr-2 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] hover:underline\"\n aria-label={`Show artist ${filterArtist.name}`}\n onClick={() => {\n if (selectedGenreUuid !== null) clearSelection();\n }}\n >\n {filterArtist.name}\n </button>\n <button\n type=\"button\"\n className=\"py-1 pl-1 pr-3 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] hover:text-[var(--color-text)]\"\n aria-label={`Clear artist filter ${filterArtist.name}`}\n onClick={() => changeArtist(null)}\n >\n ×\n </button>\n </span>\n );\n };\n\n const actions = (\n <>\n {!isLoading && !isError && (\n <GenreTreeSearch\n artistBaseUrl={artistBaseUrl}\n songBaseUrl={songBaseUrl}\n artistSearch={Boolean(artistSearch)}\n songSearch={Boolean(songSearch)}\n onArtistSelect={(artist) => { openArtist(artist.uuid); onArtistSelect?.(artist); }}\n onSongSelect={(song) => { openSong(song.uuid); onSongSelect?.(song); }}\n SearchGroups={SearchGroups}\n genrePlaylists={visibleGenrePlaylists}\n onSelect={handleGenreSearchSelect}\n onSelectGenre={(uuid) => { reopenPanel(); if (songUuid) changeSong(null); selectGenre(uuid); }}\n selectedName={activePanel?.searchName ?? null}\n onClear={activePanel?.onClose}\n showClear={activePanel !== null}\n clearLabel=\"Close panel\"\n onPrevious={handlePrevious}\n onQueryChange={onSearchQueryChange}\n onFocus={onSearchFocus}\n extraGroups={extraSearchGroups}\n />\n )}\n {!isLoading && !isError && filterArtist && (\n <div className=\"hidden w-full justify-center max-md:flex\">{renderArtistFilter()}</div>\n )}\n <div className=\"contents max-md:flex max-md:w-full max-md:items-center max-md:gap-2 max-md:overflow-x-auto max-md:[scrollbar-width:none] max-md:[&>*]:shrink-0\">\n {!isLoading && !isError && !isControlled && (\n <SegmentedControl\n aria-label=\"Tree view mode\"\n value={viewMode}\n onChange={setViewMode}\n options={[\n { value: \"pop-core\", label: \"Pop/Core\", disabled: !canShowPopCore, title: canShowPopCore ? undefined : NO_POP_ROOT_TITLE },\n { value: \"wheel\", label: \"Wheel\" },\n { value: \"stacked\", label: \"Stacked\" },\n { value: \"outline\", label: \"Outline\", disabled: !canShowPopCore, title: canShowPopCore ? undefined : NO_POP_ROOT_TITLE },\n ]}\n />\n )}\n {!isLoading && !isError && showDisplayOptions && (\n <div\n className=\"flex items-center gap-1\"\n role=\"group\"\n aria-label=\"Tree display options\"\n >\n {!isRotationControlled && viewMode !== \"stacked\" && viewMode !== \"outline\" && (\n <Button\n variant={allowWheelRotation ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={toggleWheelRotation}\n >\n Rotation\n </Button>\n )}\n </div>\n )}\n {!isLoading && !isError && !readOnly && showAddRoot && (\n <IconTextButton\n icon={Plus}\n text=\"Add root\"\n onClick={() => handleGenreCreationAction(null)}\n />\n )}\n </div>\n </>\n );\n\n return (\n <div\n data-left-panel={isPanelShown && !isCollapsed ? undefined : \"hidden\"}\n className={[\"genre-tree-view relative flex flex-col h-full\", placement === \"regions\" && REGIONS_CLASS, className]\n .filter(Boolean)\n .join(\" \")}\n >\n <div\n className={`actions-container absolute z-30 flex items-center gap-2 ${\n placement === \"regions\"\n ? \"left-[calc(var(--layout-gutter)+var(--layout-panel-inset))] top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:left-[var(--layout-panel-inset)] md:top-[var(--layout-panel-inset)] max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:top-[var(--layout-band-top)] max-md:flex-col max-md:items-stretch\"\n : \"left-5 top-5\"\n }`}\n >\n {actions}\n </div>\n {!isLoading && !isError && filterArtist && (\n <div\n className={`absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${\n placement === \"regions\" ? \"top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:top-[var(--layout-panel-inset)]\" : \"top-5\"\n }`}\n >\n {renderArtistFilter()}\n </div>\n )}\n <div className=\"content-container flex-1 min-h-0 flex flex-row gap-4\">\n <div className=\"tree-view-container relative flex-1 min-w-0 flex flex-col h-full\">\n {!isLoading && !isError && viewMode === \"outline\" && floatingControlsLeading && (\n <div className=\"absolute bottom-3 right-3 z-10\">{floatingControlsLeading}</div>\n )}\n {isLoading ? (\n <GenreTreeViewSkeleton viewMode={viewMode} />\n ) : isError ? (\n <p role=\"alert\" className=\"m-auto text-center\">\n Couldn&apos;t load the genre tree.{\" \"}\n <button type=\"button\" className=\"underline\" onClick={refetch}>\n Retry\n </button>\n </p>\n ) : viewMode === \"wheel\" ? (\n // The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,\n // and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,\n // Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.\n // The panel's own Zoom in button is hidden: the search bar carries it.\n <div className=\"tree-container search-overlay relative flex-1 w-full min-h-0 \">\n <GenreTreeWheelHandoff skeleton={<GenreTreeWheelSkeleton />} onRevealedChange={setIsWheelRevealed}>\n <GenrePlaylistTreeWheel\n scope={scope}\n genrePlaylists={visibleGenrePlaylists}\n focusUuids={focusUuids}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n selectedNodeId={selectedNodeId}\n readOnly={readOnly}\n allowWheelRotation={allowWheelRotation}\n sizeMetric={isArtistFiltered || !canSizeByViews ? \"songs\" : deferredSizeMetric}\n busy={busy}\n floatingControlsLeading={\n floatingControlsLeading || canSizeByViews ? (\n <div className=\"flex items-center gap-2\">\n {floatingControlsLeading}\n {canSizeByViews && <SizeMetricToggle value={sizeMetric} onChange={changeSizeMetric} />}\n </div>\n ) : undefined\n }\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n />\n </GenreTreeWheelHandoff>\n </div>\n ) : viewMode === \"pop-core\" ? (\n // Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.\n <div className=\"tree-container search-overlay relative flex-1 w-full min-h-0 \">\n <GenreTreeWheelHandoff skeleton={<GenreTreeWheelSkeleton />} onRevealedChange={setIsWheelRevealed}>\n <GenrePlaylistTreeWheelRadialPopCore\n scope={scope}\n genrePlaylists={visibleGenrePlaylists}\n focusUuids={focusUuids}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n selectedNodeId={selectedNodeId}\n readOnly={readOnly}\n allowWheelRotation={allowWheelRotation}\n sizeMetric={isArtistFiltered || !canSizeByViews ? \"songs\" : deferredSizeMetric}\n busy={busy}\n floatingControlsLeading={\n floatingControlsLeading || canSizeByViews ? (\n <div className=\"flex items-center gap-2\">\n {floatingControlsLeading}\n {canSizeByViews && <SizeMetricToggle value={sizeMetric} onChange={changeSizeMetric} />}\n </div>\n ) : undefined\n }\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...focus}\n />\n </GenreTreeWheelHandoff>\n </div>\n ) : viewMode === \"outline\" ? (\n <div className=\"tree-container flex-1 min-h-0 w-full overflow-y-auto relative\">\n <GenrePlaylistTreeWheelRadialPopCore\n outline\n scope={scope}\n genrePlaylists={visibleGenrePlaylists}\n focusUuids={focusUuids}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n selectedNodeId={selectedNodeId}\n readOnly={readOnly}\n />\n </div>\n ) : (\n <div className=\"tree-container relative flex flex-col gap-4 w-full pt-14 overflow-x-auto overflow-y-auto text-[var(--color-text)]\">\n {Object.entries(groupedGenrePlaylistsByRoot).map(\n ([uuid, genrePlaylistTreePerRoot]) => {\n return (\n <div\n key={uuid}\n className=\"tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg\"\n >\n <div className=\"graph-container relative z-10 h-full\">\n <GenrePlaylistTreePerRoot\n scope={scope}\n rootUuid={uuid}\n genrePlaylistTreePerRoot={genrePlaylistTreePerRoot}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n focusUuids={focusUuids}\n // Each root has its own panel; null closes the one not holding the selection.\n selectedNodeId={\n uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null\n }\n readOnly={readOnly}\n wheelZoom=\"modifier\"\n defaultViewport={\n uuid === selectedGenrePlaylist?.root.uuid ? defaultViewport : undefined\n }\n viewportRestore={\n uuid === selectedGenrePlaylist?.root.uuid && uuid === restoreRootUuid ? viewportRestore : undefined\n }\n onViewportChange={\n uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : undefined\n }\n />\n </div>\n </div>\n );\n },\n )}\n </div>\n )}\n {/* Always mounted: useObscuredInset observes the node once, so it must exist when the host mounts. */}\n <DetailPanel\n ref={panelRef}\n side=\"left\"\n title={activePanel?.title ?? \"\"}\n titleInSearch={!isLoading && !isError}\n headerAccent={activePanel?.headerAccent}\n headerActions={expandButton}\n onClose={activePanel?.onClose ?? noop}\n collapsed={isCollapsed || !isPanelShown}\n expanded={activePanel?.expanded}\n onExpandedChange={activePanel?.onExpandedChange}\n aside={activePanel?.aside}\n edgeTab={detailTab}\n >\n {activePanel?.aside && !activePanel.expanded ? (\n <>\n {activePanel.content}\n {activePanel.aside}\n </>\n ) : (\n activePanel?.content\n )}\n </DetailPanel>\n </div>\n </div>\n </div>\n );\n}\n","import { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport type GenreTreeSizeMetric = \"songs\" | \"views\";\n\nexport const hasViewsCount = (genrePlaylists: CriteriaPlaylistSimple[]): boolean =>\n genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== undefined);\n\nexport const genrePlaylistSize = (genrePlaylist: CriteriaPlaylistSimple, metric: GenreTreeSizeMetric): number => {\n if (metric === \"songs\") return genrePlaylistTrackCount(genrePlaylist);\n if (genrePlaylist.viewsCount === undefined) {\n throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);\n }\n return genrePlaylist.viewsCount;\n};\n","import type { GenreTreeNode } from \"@behindthemusictree/genre-tree-view\";\nimport type { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { genrePlaylistSize, type GenreTreeSizeMetric } from \"./size-metric\";\n\n/** The tree nodes of a set of genre playlists, as every tree renderer and the host's detail panel see them. */\nexport function toTreeNodes(\n genrePlaylists: CriteriaPlaylistSimple[],\n sizeMetric: GenreTreeSizeMetric,\n /** The open artist's footprint: every node outside it is muted. Omit it to mute nothing. */\n focusUuids?: ReadonlySet<string>,\n): GenreTreeNode[] {\n return genrePlaylists.map((genrePlaylist) => ({\n id: genrePlaylist.uuid,\n parentId: genrePlaylist.parent?.uuid ?? null,\n name: genrePlaylist.name,\n itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),\n actionable: Boolean(genrePlaylist.criteria),\n detached: !genrePlaylist.criteria,\n side: genrePlaylist.criteria?.side ?? undefined,\n wikidataId: genrePlaylist.criteria?.wikidataId ?? null,\n umbrella: genrePlaylist.isUmbrella,\n scene: genrePlaylist.scene ?? undefined,\n muted: focusUuids ? !focusUuids.has(genrePlaylist.uuid) : undefined,\n }));\n}\n","import type { GenreNodeRelations, GenreNodeStyle } from \"@behindthemusictree/genre-tree-view\";\nimport type { CriteriaPlaylistSimple, GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\n\n/**\n * How the tree draws the selected genre and its relatives, keyed by genre uuid.\n * Tree nodes are keyed by genre playlist uuid, a different id space, so the detail panel cannot look them up directly.\n */\nexport function toGenreNodeStyles(\n relations: GenreNodeRelations | null,\n genrePlaylists: CriteriaPlaylistSimple[],\n): ReadonlyMap<GenreUuid, GenreNodeStyle> {\n const styles = new Map<GenreUuid, GenreNodeStyle>();\n if (!relations) return styles;\n const genreUuidByPlaylistUuid = new Map<string, GenreUuid>(\n genrePlaylists.flatMap((genrePlaylist) => (genrePlaylist.criteria ? [[genrePlaylist.uuid, genrePlaylist.criteria.uuid] as const] : [])),\n );\n const drawn = [relations, relations.parentNode, ...relations.childNodes, ...relations.ancestorNodes];\n for (const entry of drawn) {\n const genreUuid = entry && genreUuidByPlaylistUuid.get(entry.node.id);\n if (entry && genreUuid) styles.set(genreUuid, { fill: entry.fill, textColor: entry.textColor });\n }\n return styles;\n}\n","\"use client\";\n\nimport { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { useCallback, useMemo } from \"react\";\nimport {\n GenreTree,\n getGenreTreeColor,\n type GenreTreeViewport,\n type GenreTreeProps,\n type GenreTreeAction,\n type GenreTreeNode,\n type WheelZoomMode,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaMinimum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { HostPanelProps } from \"./hostPanelProps\";\nimport { toTreeNodes } from \"./toTreeNodes\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./useGenrePlaylistPlayback\";\n\nexport type GenrePlaylistTreePerRootProps<T extends TrackBase> = {\n scope: Scope;\n className?: string;\n rootUuid: string;\n genrePlaylistTreePerRoot: CriteriaPlaylistSimple[];\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n onNodeClick?: (node: GenreTreeNode) => void;\n onNodeHover?: (node: GenreTreeNode) => void;\n /** Overrides which node is shown highlighted, e.g. from a search selection. */\n selectedNodeId?: string | null;\n /** Fires when a user action changes the info panel's node, or `null` when it is closed. */\n onSelectedNodeChange?: (node: GenreTreeNode | null) => void;\n /** When true, suppresses per-node create/rename affordances. Defaults to false. */\n readOnly?: boolean;\n wheelZoom?: WheelZoomMode;\n /** Mount-only seed for the pan/zoom, replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Runtime viewport restoration request. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** What node play buttons play; defaults to each node's whole genre playlist. */\n playback?: GenrePlaylistPlayback;\n /** The open artist's footprint; nodes outside it are drawn muted. */\n focusUuids?: ReadonlySet<string>;\n} & HostPanelProps;\n\nexport default function GenrePlaylistTreePerRoot<T extends TrackBase>({\n scope,\n className,\n rootUuid,\n genrePlaylistTreePerRoot,\n handleGenreCreationAction,\n handleGenreRenameAction,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n readOnly = false,\n wheelZoom,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n playback,\n focusUuids,\n ...hostPanel\n}: GenrePlaylistTreePerRootProps<T>) {\n const { isPlaying, setIsPlaying } = usePlayer();\n const defaultPlayback = useGenrePlaylistPlayback<T>({ scope, genrePlaylists: genrePlaylistTreePerRoot });\n const { playing, play } = playback ?? defaultPlayback;\n const playingNodeId = playing?.uuid ?? null;\n\n const nodes = useMemo(\n () => toTreeNodes(genrePlaylistTreePerRoot, \"songs\", focusUuids),\n [genrePlaylistTreePerRoot, focusUuids],\n );\n\n const handlePlayPause = useCallback(\n (nodeId: string) => {\n const genrePlaylist = genrePlaylistTreePerRoot.find((g) => g.uuid === nodeId);\n if (!genrePlaylist) return;\n\n if (nodeId === playingNodeId) {\n setIsPlaying(!isPlaying);\n return;\n }\n\n if (genrePlaylistTrackCount(genrePlaylist) === 0) {\n return;\n }\n\n void play(genrePlaylist);\n },\n [\n genrePlaylistTreePerRoot,\n playingNodeId,\n isPlaying,\n setIsPlaying,\n play,\n ],\n );\n\n const handleAddChild = useCallback(\n (parentId: string) => {\n const genrePlaylist = genrePlaylistTreePerRoot.find((g) => g.uuid === parentId);\n if (!genrePlaylist?.criteria) return;\n handleGenreCreationAction(genrePlaylist.criteria);\n },\n [genrePlaylistTreePerRoot, handleGenreCreationAction],\n );\n\n const handleRenameRequest = useCallback(\n (node: GenreTreeNode) => {\n const genrePlaylist = genrePlaylistTreePerRoot.find((g) => g.uuid === node.id);\n if (!genrePlaylist?.criteria) return;\n handleGenreRenameAction(genrePlaylist.criteria);\n },\n [genrePlaylistTreePerRoot, handleGenreRenameAction],\n );\n\n const handleDeleteRequest = useCallback((node: GenreTreeNode) => {\n if (confirm(`Are you sure you want to delete \"${node.name}\"?`)) {\n // TODO: Implement delete genre\n }\n }, []);\n\n return (\n <GenreTree\n className={className}\n nodes={nodes}\n rootColor={getGenreTreeColor(rootUuid)}\n playingNodeId={playingNodeId}\n playState={isPlaying ? \"playing\" : \"paused\"}\n onPlayPause={handlePlayPause}\n onAddChild={readOnly ? undefined : handleAddChild}\n onRenameRequest={readOnly ? undefined : handleRenameRequest}\n onDeleteRequest={readOnly ? undefined : handleDeleteRequest}\n additionalActions={additionalActions}\n onNodeClick={onNodeClick}\n onNodeHover={onNodeHover}\n selectedNodeId={selectedNodeId}\n onSelectedNodeChange={onSelectedNodeChange}\n wheelZoom={wheelZoom}\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...hostPanel}\n />\n );\n}\n","\"use client\";\n\nimport { useCallback, useMemo } from \"react\";\nimport {\n TrackListOriginType, TracksFailureAlreadyReportedError, useTrackList, GenreCatalogueCountsSchema,\n defaultGenreMusicSelection, genreMusicSelectionKey,\n type GenreMusicSelection,\n type CriteriaPlaylistMinimum, type CriteriaPlaylistSimple, type TrackBase,\n type TrackListOriginFromCriteriaPlaylist,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport { AppError, ErrorCode, type Scope } from \"@behindthemusictree/app-kit/transport\";\nimport InternalErrorPopup from \"../../popup/InternalErrorPopup\";\n\nexport type PlayableGenrePlaylistInput = CriteriaPlaylistMinimum & { criteria?: CriteriaPlaylistSimple[\"criteria\"] };\n/** The playlist loaded in the player; `selectionKey` is `genreMusicSelectionKey(selection).join()`, empty without a selection. */\nexport type PlayingGenrePlaylist = { uuid: string; selectionKey: string };\nexport type GenrePlaylistPlayback = {\n playing: PlayingGenrePlaylist | null;\n /**\n * Plays `genrePlaylist`; `selection` overrides the default coverage of a reference genre. Never rejects: connectivity\n * errors reach the global popup through the backend request layer, any other failure is shown here with its real code.\n */\n play: (genrePlaylist: PlayableGenrePlaylistInput, selection?: GenreMusicSelection) => Promise<void>;\n};\nexport type UseGenrePlaylistPlaybackOptions = {\n scope: Scope;\n genrePlaylists: CriteriaPlaylistSimple[];\n artist?: { uuid: string; name: string } | null;\n};\n\nexport function useGenrePlaylistPlayback<T extends TrackBase = TrackBase>({\n scope, genrePlaylists, artist = null,\n}: UseGenrePlaylistPlaybackOptions): GenrePlaylistPlayback {\n const { trackList, playNewTrackListFromGenrePlaylist } = useTrackList<T>();\n const { showPopup } = usePopup();\n const origin = trackList?.origin;\n const playing = useMemo<PlayingGenrePlaylist | null>(() => {\n if (!origin || origin.type !== TrackListOriginType.GENRE_PLAYLIST || origin.scope !== scope) return null;\n const playlistOrigin = origin as TrackListOriginFromCriteriaPlaylist;\n if (playlistOrigin.artistUuid !== artist?.uuid) return null;\n const playlist = genrePlaylists.find((item) => item.uuid === origin.uuid) ?? playlistOrigin.criteriaPlaylist;\n const expected = scope === \"reference\" && playlist && !(\"criteria\" in playlist && playlist.criteria === null)\n ? defaultGenreMusicSelection(GenreCatalogueCountsSchema.parse(playlist)) : undefined;\n return { uuid: origin.uuid, selectionKey: genreMusicSelectionKey(playlistOrigin.selection ?? expected).join() };\n }, [origin, artist, genrePlaylists, scope]);\n\n const play = useCallback(async (playlist: PlayableGenrePlaylistInput, requested?: GenreMusicSelection) => {\n if (artist && !playlist.criteria) return;\n try {\n const selection = scope === \"reference\" && playlist.criteria !== null\n ? requested ?? defaultGenreMusicSelection(GenreCatalogueCountsSchema.parse(playlist)) : undefined;\n await (selection || artist\n ? playNewTrackListFromGenrePlaylist(playlist, scope, { selection, ...(artist && { artistUuid: artist.uuid }) })\n : playNewTrackListFromGenrePlaylist(playlist, scope));\n } catch (error) {\n console.error(\"Failed to load genre playlist tracks:\", error);\n if (error instanceof TracksFailureAlreadyReportedError) return;\n showPopup(<InternalErrorPopup errorCode={error instanceof AppError ? error.code : ErrorCode.CLIENT_UNKNOWN} />);\n }\n }, [artist, scope, playNewTrackListFromGenrePlaylist, showPopup]);\n\n return useMemo(() => ({ playing, play }), [playing, play]);\n}\n","\"use client\";\n\nimport { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { useCallback, useMemo, type ReactNode } from \"react\";\nimport {\n GenreTreeWheel,\n type GenreTreeViewport,\n type GenreTreeProps,\n type GenreTreeAction,\n type GenreTreeNode,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaMinimum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { HostPanelProps } from \"./hostPanelProps\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./useGenrePlaylistPlayback\";\nimport type { GenreTreeSizeMetric } from \"./size-metric\";\nimport { toTreeNodes } from \"./toTreeNodes\";\n\nexport type GenrePlaylistTreeWheelProps<T extends TrackBase> = {\n scope: Scope;\n className?: string;\n genrePlaylists: CriteriaPlaylistSimple[];\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n onNodeClick?: (node: GenreTreeNode) => void;\n onNodeHover?: (node: GenreTreeNode) => void;\n /** Overrides which node is shown highlighted, e.g. from a search selection. */\n selectedNodeId?: string | null;\n /** Fires when a user action changes the info panel's node, or `null` when it is closed. */\n onSelectedNodeChange?: (node: GenreTreeNode | null) => void;\n /** When true, suppresses per-node create/rename affordances. Defaults to false. */\n readOnly?: boolean;\n /** When false, clicking a chip still selects its root, but the wheel doesn't spin to the\n * anchor. Defaults to true. */\n allowWheelRotation?: boolean;\n /** What node size is proportional to; defaults to the song count. */\n sizeMetric?: GenreTreeSizeMetric;\n /** Rendered in the floating controls, beside the zoom buttons. */\n floatingControlsLeading?: ReactNode;\n /** Shows the tree's busy indicator while the data behind it is changing. */\n busy?: boolean;\n /** Mount-only seed for the pan/zoom, replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Runtime viewport restoration request. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** What node play buttons play; defaults to each node's whole genre playlist. */\n playback?: GenrePlaylistPlayback;\n /** The open artist's footprint; nodes outside it are drawn muted. */\n focusUuids?: ReadonlySet<string>;\n} & HostPanelProps;\n\nexport default function GenrePlaylistTreeWheel<T extends TrackBase>({\n scope,\n className,\n genrePlaylists,\n handleGenreCreationAction,\n handleGenreRenameAction,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n readOnly = false,\n allowWheelRotation,\n sizeMetric = \"songs\",\n floatingControlsLeading,\n busy,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n playback,\n focusUuids,\n ...hostPanel\n}: GenrePlaylistTreeWheelProps<T>) {\n const { isPlaying, setIsPlaying } = usePlayer();\n const defaultPlayback = useGenrePlaylistPlayback<T>({ scope, genrePlaylists });\n const { playing, play } = playback ?? defaultPlayback;\n const playingNodeId = playing?.uuid ?? null;\n\n const nodes = useMemo(\n () => toTreeNodes(genrePlaylists, sizeMetric, focusUuids),\n [genrePlaylists, sizeMetric, focusUuids],\n );\n\n const handlePlayPause = useCallback(\n (nodeId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);\n if (!genrePlaylist) return;\n\n if (nodeId === playingNodeId) {\n setIsPlaying(!isPlaying);\n return;\n }\n\n if (genrePlaylistTrackCount(genrePlaylist) === 0) {\n return;\n }\n\n void play(genrePlaylist);\n },\n [\n genrePlaylists,\n playingNodeId,\n isPlaying,\n setIsPlaying,\n play,\n ],\n );\n\n const handleAddChild = useCallback(\n (parentId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === parentId);\n if (!genrePlaylist?.criteria) return;\n handleGenreCreationAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreCreationAction],\n );\n\n const handleRenameRequest = useCallback(\n (node: GenreTreeNode) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === node.id);\n if (!genrePlaylist?.criteria) return;\n handleGenreRenameAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreRenameAction],\n );\n\n const handleDeleteRequest = useCallback((node: GenreTreeNode) => {\n if (confirm(`Are you sure you want to delete \"${node.name}\"?`)) {\n // TODO: Implement delete genre\n }\n }, []);\n\n return (\n <GenreTreeWheel\n className={className}\n nodes={nodes}\n playingNodeId={playingNodeId}\n playState={isPlaying ? \"playing\" : \"paused\"}\n onPlayPause={handlePlayPause}\n onAddChild={readOnly ? undefined : handleAddChild}\n onRenameRequest={readOnly ? undefined : handleRenameRequest}\n onDeleteRequest={readOnly ? undefined : handleDeleteRequest}\n additionalActions={additionalActions}\n onNodeClick={onNodeClick}\n onNodeHover={onNodeHover}\n selectedNodeId={selectedNodeId}\n onSelectedNodeChange={onSelectedNodeChange}\n allowWheelRotation={allowWheelRotation}\n floatingControlsLeading={floatingControlsLeading}\n busy={busy}\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...hostPanel}\n />\n );\n}\n","\"use client\";\n\nimport { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { useCallback, useMemo, type ReactNode } from \"react\";\nimport {\n GenreTreeOutline,\n GenreTreeWheelRadialPopCore,\n type GenreTreeViewport,\n type GenreTreeProps,\n type FocusChangeReason,\n type GenreTreeAction,\n type GenreTreeNode,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaMinimum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { HostPanelProps } from \"./hostPanelProps\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./useGenrePlaylistPlayback\";\nimport type { GenreTreeSizeMetric } from \"./size-metric\";\nimport { toTreeNodes } from \"./toTreeNodes\";\n\n/** Pop-core focus is controlled-only: pass both props or neither. Ignored in outline mode. */\nexport type GenreFocusProps =\n | { focusGenreUuid?: undefined; onFocusGenreChange?: undefined }\n | {\n /** Zooms the pop-core wheel into this genre's subtree. An unknown or non-zoomable uuid shows\n * the whole tree and fires `onFocusGenreChange(null, \"rejected\")`. */\n focusGenreUuid: string | null;\n /** Fires with the genre to focus and why: `\"zoom-in\"` / `\"back\"` (parent) / `\"previous\"` /\n * `\"root\"` from the user's zoom controls, `\"search\"` when a selection outside the zoom refocuses\n * to its top-level root (null for Mainstream Pop), and\n * `\"rejected\"` when an invalid `focusGenreUuid` is reset to null. */\n onFocusGenreChange: (uuid: string | null, reason: FocusChangeReason) => void;\n };\n\nexport type GenrePlaylistTreeWheelRadialPopCoreProps<T extends TrackBase> = {\n scope: Scope;\n className?: string;\n genrePlaylists: CriteriaPlaylistSimple[];\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n onNodeClick?: (node: GenreTreeNode) => void;\n onNodeHover?: (node: GenreTreeNode) => void;\n /** Overrides which node is shown highlighted, e.g. from a search selection. */\n selectedNodeId?: string | null;\n /** Fires when a user action changes the info panel's node, or `null` when it is closed. */\n onSelectedNodeChange?: (node: GenreTreeNode | null) => void;\n /** When true, suppresses per-node create/rename affordances. Defaults to false. */\n readOnly?: boolean;\n /** When false, clicking a chip still selects its root, but the ring doesn't spin to the\n * landing angle. Defaults to true. */\n allowWheelRotation?: boolean;\n /** What node size is proportional to; defaults to the song count. */\n sizeMetric?: GenreTreeSizeMetric;\n /** Rendered in the floating controls, beside the zoom buttons. */\n floatingControlsLeading?: ReactNode;\n /** Shows the tree's busy indicator while the data behind it is changing; ignored in outline mode. */\n busy?: boolean;\n /** When true, renders the same forest as GenreTreeOutline's nested-list text view instead of\n * the radial wheel. Defaults to false. */\n outline?: boolean;\n /** Mount-only seed for the pan/zoom, replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Runtime viewport restoration request. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** What node play buttons play; defaults to each node's whole genre playlist. */\n playback?: GenrePlaylistPlayback;\n /** The open artist's footprint; nodes outside it are drawn muted. */\n focusUuids?: ReadonlySet<string>;\n} & GenreFocusProps &\n HostPanelProps;\n\nexport default function GenrePlaylistTreeWheelRadialPopCore<T extends TrackBase>(\n props: GenrePlaylistTreeWheelRadialPopCoreProps<T>,\n) {\n const {\n scope,\n className,\n genrePlaylists,\n handleGenreCreationAction,\n handleGenreRenameAction,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n readOnly = false,\n allowWheelRotation,\n sizeMetric = \"songs\",\n floatingControlsLeading,\n busy,\n outline = false,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n playback,\n } = props;\n const focus: GenreFocusProps = props;\n const hostPanel: HostPanelProps = {\n obscuredInset: props.obscuredInset,\n onNodeStyleResolverChange: props.onNodeStyleResolverChange,\n };\n const { isPlaying, setIsPlaying } = usePlayer();\n const defaultPlayback = useGenrePlaylistPlayback<T>({ scope, genrePlaylists });\n const { playing, play } = playback ?? defaultPlayback;\n const playingNodeId = playing?.uuid ?? null;\n\n const nodes = useMemo(() => toTreeNodes(genrePlaylists, sizeMetric, props.focusUuids), [genrePlaylists, sizeMetric, props.focusUuids]);\n\n const handlePlayPause = useCallback(\n (nodeId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);\n if (!genrePlaylist) return;\n\n if (nodeId === playingNodeId) {\n setIsPlaying(!isPlaying);\n return;\n }\n\n if (genrePlaylistTrackCount(genrePlaylist) === 0) {\n return;\n }\n\n void play(genrePlaylist);\n },\n [genrePlaylists, playingNodeId, isPlaying, setIsPlaying, play],\n );\n\n const handleAddChild = useCallback(\n (parentId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === parentId);\n if (!genrePlaylist?.criteria) return;\n handleGenreCreationAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreCreationAction],\n );\n\n const handleRenameRequest = useCallback(\n (node: GenreTreeNode) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === node.id);\n if (!genrePlaylist?.criteria) return;\n handleGenreRenameAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreRenameAction],\n );\n\n const handleDeleteRequest = useCallback((node: GenreTreeNode) => {\n if (confirm(`Are you sure you want to delete \"${node.name}\"?`)) {\n // TODO: Implement delete genre\n }\n }, []);\n\n const treeProps = {\n className,\n nodes,\n playingNodeId,\n playState: isPlaying ? (\"playing\" as const) : (\"paused\" as const),\n onPlayPause: handlePlayPause,\n onAddChild: readOnly ? undefined : handleAddChild,\n onRenameRequest: readOnly ? undefined : handleRenameRequest,\n onDeleteRequest: readOnly ? undefined : handleDeleteRequest,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n ...hostPanel,\n };\n\n return outline ? (\n <GenreTreeOutline {...treeProps} />\n ) : (\n <GenreTreeWheelRadialPopCore\n {...treeProps}\n allowWheelRotation={allowWheelRotation}\n floatingControlsLeading={floatingControlsLeading}\n busy={busy}\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...(focus.onFocusGenreChange\n ? { focusNodeId: focus.focusGenreUuid, onFocusChange: focus.onFocusGenreChange }\n : { focusNodeId: undefined, onFocusChange: undefined })}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type GenreTreeWheelHandoffProps = {\n skeleton: React.ReactNode;\n children: React.ReactNode;\n /** Called with `true` once `children` is revealed, and with `false` when the handoff unmounts. */\n onRevealedChange?: (revealed: boolean) => void;\n};\n\n/**\n * Keeps `skeleton` fully opaque over `children` for the first two animation frames after\n * `children` mounts, then cross-fades to `children`.\n *\n * `children` is one of genre-tree-view's wheel components (`GenreTreeWheel` /\n * `GenreTreeWheelRadialPopCore`), which compute their own pan/zoom \"fit to frame\" in a passive\n * effect (`hasInitialFitRef`) that runs *after* their first paint. Without this handoff, that\n * first paint — unfit, `translate(0,0) scale(1)` — is briefly visible the instant the skeleton is\n * swapped out, which reads as a flash/jump right as loading finishes. Two nested\n * `requestAnimationFrame` calls reliably span that effect's own render-commit-paint cycle, so\n * `children` has had time to begin layout before it is revealed. Viewport restoration waits for\n * measurable geometry independently of this visual handoff.\n *\n * Remounting this component (e.g. via a `key` change, or the parent unmounting/remounting the\n * branch that renders it) restarts the handoff, which is what's wanted any time `children` itself\n * is about to mount fresh and re-run its own fit-to-frame effect.\n */\nexport function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }: GenreTreeWheelHandoffProps) {\n const [revealed, setRevealed] = useState(false);\n const onRevealedChangeRef = useRef(onRevealedChange);\n onRevealedChangeRef.current = onRevealedChange;\n\n useEffect(() => {\n let innerFrame = 0;\n const outerFrame = requestAnimationFrame(() => {\n innerFrame = requestAnimationFrame(() => {\n setRevealed(true);\n onRevealedChangeRef.current?.(true);\n });\n });\n return () => {\n onRevealedChangeRef.current?.(false);\n cancelAnimationFrame(outerFrame);\n cancelAnimationFrame(innerFrame);\n };\n }, []);\n\n return (\n <div className=\"relative w-full h-full\">\n <div\n className=\"absolute inset-0 transition-opacity duration-150 ease-out\"\n style={{ opacity: revealed ? 1 : 0, pointerEvents: revealed ? \"auto\" : \"none\" }}\n aria-hidden={!revealed}\n >\n {children}\n </div>\n {!revealed && (\n <div className=\"absolute inset-0\" aria-hidden=\"true\">\n {skeleton}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useDeferredValue, useState, type ComponentType, type ReactNode } from \"react\";\nimport type { GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\nimport GenreSearch, { type GenreSearchProps } from \"./GenreSearch\";\nimport { useArtistSearchGroup, useSongSearchGroup, type SearchGroup } from \"./search\";\n\nexport interface GenreSearchGroupsProps {\n query: string;\n focused: boolean;\n onSelectGenre: (uuid: GenreUuid) => void;\n children: (groups: SearchGroup[]) => ReactNode;\n}\n\ntype Props = GenreSearchProps & {\n artistBaseUrl: () => string;\n songBaseUrl: () => string;\n onArtistSelect: Parameters<typeof useArtistSearchGroup>[2];\n onSongSelect: Parameters<typeof useSongSearchGroup>[2];\n artistSearch: boolean;\n songSearch: boolean;\n SearchGroups?: ComponentType<GenreSearchGroupsProps>;\n onSelectGenre: (uuid: GenreUuid) => void;\n};\n\n/** Keep typed query updates and remote results inside the search subtree. */\nexport function GenreTreeSearch({\n artistBaseUrl, songBaseUrl, onArtistSelect, onSongSelect, artistSearch, songSearch,\n SearchGroups, onSelectGenre, extraGroups = [], onQueryChange, onFocus, ...props\n}: Props) {\n const [query, setQuery] = useState(\"\");\n const [focused, setFocused] = useState(false);\n const deferredQuery = useDeferredValue(query);\n const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);\n const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);\n const render = (hostGroups: SearchGroup[]) => (\n <GenreSearch\n {...props}\n onQueryChange={(text) => {\n setQuery(text);\n onQueryChange?.(text);\n }}\n onFocus={() => {\n setFocused(true);\n onFocus?.();\n }}\n extraGroups={[...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group): group is SearchGroup => group !== undefined)}\n />\n );\n return SearchGroups\n ? <SearchGroups query={deferredQuery} focused={focused} onSelectGenre={onSelectGenre}>{render}</SearchGroups>\n : render([]);\n}\n","\"use client\";\n\nimport { ArrowLeft } from \"lucide-react\";\nimport { SEARCH_LEADING_BUTTON_CLASS } from \"@behindthemusictree/ui\";\n\nimport { CriteriaPlaylistSimple, useGenreSearch } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { SearchBox, type SearchGroup } from \"./search\";\n\n/** @deprecated Use `SearchGroup`. */\nexport type GenreSearchExtraGroup = SearchGroup;\n\nexport type GenreSearchProps<T extends CriteriaPlaylistSimple = CriteriaPlaylistSimple> = {\n genrePlaylists: T[];\n onSelect: (genrePlaylist: T) => void;\n /** Name of the currently selected genre; fills the input whenever it changes. */\n selectedName?: string | null;\n /** When set, renders a \"Previous\" button left of the text and makes room for it. */\n onPrevious?: () => void;\n /** Called by the clear button, after it empties the input. */\n onClear?: () => void;\n /** Forces the clear button on or off; by default it shows while the input has something to clear. */\n showClear?: boolean;\n clearLabel?: string;\n placeholder?: string;\n /** Called with what the user types, and with \"\" on clear or pick; never when `selectedName` refills the input. */\n onQueryChange?: (query: string) => void;\n /** Further result groups (places, artists, songs) the host resolves from `onQueryChange`. */\n extraGroups?: SearchGroup[];\n /** Called when the input gains focus. */\n onFocus?: () => void;\n};\n\nexport default function GenreSearch<T extends CriteriaPlaylistSimple = CriteriaPlaylistSimple>({\n genrePlaylists,\n onSelect,\n selectedName = null,\n onClear,\n showClear,\n clearLabel,\n onPrevious,\n placeholder,\n onQueryChange,\n extraGroups = [],\n onFocus,\n}: GenreSearchProps<T>) {\n const { query, setQuery, results, canClear, clear, select } = useGenreSearch({\n genrePlaylists,\n onSelect,\n selectedName,\n onClear,\n });\n\n const active = query !== \"\" && query !== selectedName;\n const hasExtras = extraGroups.length > 0;\n const label = hasExtras ? \"Search\" : \"Search a genre\";\n\n const groups: SearchGroup[] = [\n {\n key: \"genres\",\n label: hasExtras ? \"Genres\" : undefined,\n items: results.map((genrePlaylist) => ({\n key: genrePlaylist.uuid,\n content: (\n <>\n {genrePlaylist.name}\n {genrePlaylist.isUmbrella && (\n <span className=\"ml-2 text-caption italic text-[var(--color-text-muted)]\">umbrella</span>\n )}\n </>\n ),\n onSelect: () => select(genrePlaylist),\n })),\n },\n ...extraGroups.map((group) =>\n active\n ? group\n : { ...group, items: [], status: \"\", loading: false },\n ),\n ];\n\n return (\n <div className=\"genre-search w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 max-md:w-full\">\n <SearchBox\n label={label}\n placeholder={placeholder}\n value={query}\n onValueChange={(value) => {\n setQuery(value);\n onQueryChange?.(value);\n }}\n groups={groups}\n onPicked={(groupKey) => {\n if (groupKey !== \"genres\") setQuery(\"\");\n onQueryChange?.(\"\");\n }}\n clearLabel={clearLabel}\n onClear={\n (showClear ?? canClear)\n ? () => {\n clear();\n onQueryChange?.(\"\");\n }\n : undefined\n }\n leading={\n onPrevious && (\n <button type=\"button\" aria-label=\"Previous\" title=\"Previous\" className={SEARCH_LEADING_BUTTON_CLASS} onClick={onPrevious}>\n <ArrowLeft aria-hidden=\"true\" className=\"h-4 w-4\" />\n </button>\n )\n }\n onFocus={onFocus}\n />\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\nimport { SearchCombobox } from \"@behindthemusictree/ui\";\n\nimport type { SearchGroup } from \"./SearchGroup\";\n\nexport type SearchBoxProps = {\n /** Accessible name of the input and the list. */\n label: string;\n placeholder?: string;\n value: string;\n onValueChange: (value: string) => void;\n groups: SearchGroup[];\n /** Called after the group item is picked and the list closed. */\n onPicked?: (groupKey: string, itemKey: string) => void;\n /** Shows the clear button when set. */\n onClear?: () => void;\n clearLabel?: string;\n /** An action left of the text, e.g. a Previous button. */\n leading?: ReactNode;\n className?: string;\n /** Called when the input gains focus, e.g. to load an index lazily. */\n onFocus?: () => void;\n};\n\n/** A search pill over any number of result groups; picking an item calls that item's `onSelect`. */\nexport default function SearchBox({\n label,\n placeholder,\n value,\n onValueChange,\n groups,\n onPicked,\n onClear,\n clearLabel,\n leading,\n className,\n onFocus,\n}: SearchBoxProps) {\n const [open, setOpen] = useState(false);\n const loading = groups.some((group) => group.loading);\n const status = groups\n .map((group) => group.status)\n .filter(Boolean)\n .join(\". \");\n\n const handlePick = (groupKey: string, itemKey: string) => {\n setOpen(false);\n groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();\n onPicked?.(groupKey, itemKey);\n };\n\n return (\n <div className={className} onFocusCapture={onFocus}>\n <SearchCombobox\n ariaLabel={label}\n listLabel={`${label} results`}\n value={value}\n placeholder={placeholder ?? `${label}…`}\n groups={groups.map((group) => ({\n key: group.key,\n label: group.label,\n options: group.items.map((item) => ({ key: item.key, content: item.content })),\n }))}\n open={open}\n onOpenChange={setOpen}\n onValueChange={onValueChange}\n onPick={handlePick}\n status={status}\n loading={loading}\n onClear={onClear}\n clearLabel={clearLabel}\n leading={leading}\n inputClassName=\"focus-visible:ring-0\"\n />\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\n\nexport type SearchGroupItem = { key: string; content: ReactNode; onSelect: () => void };\n\n/** One headed list of results in a `SearchBox`, resolved by the host or by a group hook. */\nexport type SearchGroup = {\n key: string;\n /** Heading of the group; omitted when it is the only one. */\n label?: string;\n items: SearchGroupItem[];\n /** Announced politely, e.g. \"No artists found\". */\n status?: string;\n /** Shows a spinner in place of the search icon while this group resolves. */\n loading?: boolean;\n};\n\nexport const SEARCH_FAILED_STATUS = \"Search failed\";\n\n/** \"Search failed\" on error, \"No <noun> found\" once settled and empty, else \"\". */\nexport const searchStatus = (\n state: { isError: boolean; settled: boolean },\n count: number,\n noun: string,\n): string => (state.isError ? SEARCH_FAILED_STATUS : state.settled && count === 0 ? `No ${noun} found` : \"\");\n","\"use client\";\n\nimport { useArtistSearch, type ArtistSearchResult } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { searchStatus, type SearchGroup } from \"./SearchGroup\";\n\nexport function useArtistSearchGroup(\n getBaseUrl: () => string,\n text: string,\n onSelect: (artist: ArtistSearchResult) => void,\n enabled = true,\n): SearchGroup | undefined {\n const search = useArtistSearch(getBaseUrl, enabled ? text : \"\");\n if (!enabled) return undefined;\n return {\n key: \"artists\",\n label: \"Artists\",\n items: search.artists.map((artist) => ({\n key: artist.uuid,\n content: (\n <>\n <span className=\"block truncate font-medium\">\n {artist.name}\n {artist.disambiguation && (\n <span className=\"font-normal text-[var(--color-neutral-500)]\"> · {artist.disambiguation}</span>\n )}\n </span>\n {artist.matchedAlias && (\n <span className=\"block truncate text-caption text-[var(--color-neutral-500)]\">also known as {artist.matchedAlias}</span>\n )}\n </>\n ),\n onSelect: () => onSelect(artist),\n })),\n status: searchStatus(search, search.artists.length, \"artists\"),\n loading: search.pending,\n };\n}\n","\"use client\";\n\nimport {\n isSongSearchResultPlayable,\n useSongSearch,\n type SongSearchResult,\n} from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { searchStatus, type SearchGroup } from \"./SearchGroup\";\n\nexport function useSongSearchGroup(\n getBaseUrl: () => string,\n text: string,\n onSelect: (song: SongSearchResult) => void,\n enabled = true,\n): SearchGroup | undefined {\n const search = useSongSearch(getBaseUrl, enabled ? text : \"\");\n if (!enabled) return undefined;\n return {\n key: \"songs\",\n label: \"Songs\",\n items: search.songs.map((song) => ({\n key: song.uuid,\n content: (\n <span className={isSongSearchResultPlayable(song) ? undefined : \"opacity-60\"}>\n <span className=\"block truncate font-medium\">{song.title}</span>\n <span className=\"block truncate text-caption text-[var(--color-neutral-500)]\">\n {[song.artists.map((artist) => artist.name).join(\", \"), song.genre?.name ?? \"No genre\"].filter(Boolean).join(\" · \")}\n </span>\n </span>\n ),\n onSelect: () => onSelect(song),\n })),\n status: searchStatus(search, search.songs.length, \"songs\"),\n loading: search.pending,\n };\n}\n","\"use client\";\n\nimport {\n useGenreRemoteSearch,\n type GenreSearchResult,\n type UseGenreRemoteSearchOptions,\n} from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { searchStatus, type SearchGroup } from \"./SearchGroup\";\n\nexport type UseGenreRemoteSearchGroupOptions = UseGenreRemoteSearchOptions & {\n key?: string;\n label?: string;\n /** Drops hits the host already lists elsewhere. */\n filter?: (genre: GenreSearchResult) => boolean;\n /** Extra secondary text per hit, e.g. the region. */\n describe?: (genre: GenreSearchResult) => string | undefined;\n};\n\n/** Genres from the API's ranked `genres/search/`, rendered with the umbrella tag and the tree they live in. */\nexport function useGenreRemoteSearchGroup(\n getBaseUrl: () => string,\n text: string,\n onSelect: (genre: GenreSearchResult) => void,\n { key = \"genres\", label = \"Genres\", filter, describe, ...options }: UseGenreRemoteSearchGroupOptions = {},\n): SearchGroup {\n const search = useGenreRemoteSearch(getBaseUrl, text, options);\n const genres = filter ? search.genres.filter(filter) : search.genres;\n return {\n key,\n label,\n items: genres.map((genre) => ({\n key: genre.uuid,\n content: (\n <>\n <span className=\"block truncate font-medium\">\n {genre.name}\n {genre.isUmbrella && <span className=\"ml-2 text-caption font-normal italic text-[var(--color-text-muted)]\">umbrella</span>}\n </span>\n <span className=\"block truncate text-caption text-[var(--color-neutral-500)]\">\n {describe?.(genre) ?? `${genre.treeName} · ${genre.root.name}`}\n </span>\n </>\n ),\n onSelect: () => onSelect(genre),\n })),\n status: searchStatus(search, genres.length, \"genres\"),\n loading: search.pending,\n };\n}\n","\"use client\";\n\nimport { useMemo, type ReactNode, type ComponentProps } from \"react\";\nimport {\n GenreNodeAncestors,\n GenreNodeFamily,\n getGenreTreeColor,\n getTextColorOnFill,\n TEXT_COLOR,\n tintSurface,\n type GenreNodeStyle,\n type GenreTreeNode,\n type InfoPanelChild,\n} from \"@behindthemusictree/genre-tree-view\";\nimport { DetailPanel, IconButton, Skeleton } from \"@behindthemusictree/ui\";\nimport { Maximize2, Minimize2 } from \"lucide-react\";\n\nimport {\n useFetchGenreDetail,\n genreMusicCount,\n GenrePlaylistSummarySchema,\n GenreCatalogueCountsSchema,\n CriteriaMinimumSchema,\n type CriteriaPlaylistSimple,\n type CriteriaMinimum,\n type CriteriaOverview,\n type GenreUuid,\n GenreUuidSchema,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\n\nimport { GenreInfoPanelBody, type GenreInfoPanelBodyProps } from \"./GenreInfoPanelBody\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport { useGenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\n\nexport type GenreDetailPanelProps<O extends CriteriaOverview> = {\n /** May be a raw URL value: one that names no genre renders \"Genre not found\". */\n genreUuid: string;\n scope: Scope;\n getBackendBaseUrl: () => string;\n onClose: () => void;\n /** Fired with the uuid of a family or ancestor chip the user picked. */\n onSelectGenre: (genreUuid: GenreUuid) => void;\n /** When set, the panel offers \"Focus\". */\n onZoomIn?: () => void;\n /** Absolute or relative URL that shares this genre; the share action shows only when set. */\n shareUrl?: string;\n shareTarget?: GenreTreeShareTarget;\n collapsed?: boolean;\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** Tab on the panel's inner edge, for hosts that hide and show the panel. */\n edgeTab?: ComponentProps<typeof DetailPanel>[\"edgeTab\"];\n extras?: GenreInfoPanelBodyProps<O>[\"extras\"];\n /** The host's search field shows this genre's name and closes the panel. */\n titleInSearch?: boolean;\n};\n\n// Relatives from the detail endpoint carry no song count, so the family dots share one size.\nconst RELATIVE_ITEM_COUNT = 1;\n\nfunction toNode(genre: CriteriaMinimum, parentId: string | null): GenreTreeNode {\n return {\n id: genre.uuid,\n parentId,\n name: genre.name,\n itemCount: RELATIVE_ITEM_COUNT,\n side: genre.side ?? undefined,\n wikidataId: genre.wikidataId,\n };\n}\n\ntype GenreDetailContentOptions<O extends CriteriaOverview> = {\n genreUuid: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n onSelectGenre: (uuid: GenreUuid) => void;\n extras?: GenreInfoPanelBodyProps<O>[\"extras\"];\n band?: Partial<GenreInfoPanelBodyProps<O>[\"band\"]>;\n playback?: GenreInfoPanelBodyProps<O>[\"playback\"];\n trailing?: ReactNode;\n genrePlaylist?: CriteriaPlaylistSimple;\n expanded?: boolean;\n /** How the mounted tree draws this genre and its relatives, by genre uuid; genres it omits fall back to the root color. */\n treeStyles?: ReadonlyMap<GenreUuid, GenreNodeStyle>;\n};\n\n/** Shared entity data and content; the host owns the panel shell and placement. */\nexport function useGenreDetailContent<O extends CriteriaOverview>({\n genreUuid, scope, getBackendBaseUrl, onSelectGenre, extras, band, playback: hostPlayback, trailing, genrePlaylist: hostPlaylist, expanded, treeStyles,\n}: GenreDetailContentOptions<O>) {\n const result = useFetchGenreDetail(genreUuid, scope, getBackendBaseUrl);\n const detail = result.status === \"success\" ? result.genre : undefined;\n const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });\n const playback = hostPlayback ?? defaultPlayback;\n\n const view = useMemo(() => {\n if (!detail) return null;\n const rootColor = getGenreTreeColor(detail.root.wikidataId);\n const relative = (genre: CriteriaMinimum, parentId: string | null): InfoPanelChild => ({\n node: toNode(genre, parentId),\n ...(treeStyles?.get(genre.uuid) ?? { fill: tintSurface(rootColor), textColor: TEXT_COLOR }),\n });\n const ancestors = [...detail.ascendants].sort((a, b) => b.degree - a.degree);\n const own = treeStyles?.get(detail.uuid) ?? { fill: rootColor, textColor: getTextColorOnFill(rootColor) };\n return {\n node: {\n id: detail.uuid,\n parentId: detail.parent?.uuid ?? null,\n name: detail.name,\n itemCount: scope === \"reference\" ? genreMusicCount(detail.criteriaPlaylist ? GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist) : GenreCatalogueCountsSchema.parse(detail.catalogue)) : detail.tracksCount,\n wikidataId: detail.wikidataId,\n } satisfies GenreTreeNode,\n fill: own.fill,\n textColor: own.textColor,\n parentNode: detail.parent ? relative(detail.parent, null) : null,\n childNodes: detail.children.map((child) => relative(child, detail.uuid)),\n ancestorNodes: ancestors.map(({ ascendant }, index) =>\n relative(ascendant, index === 0 ? null : ancestors[index - 1].ascendant.uuid),\n ),\n };\n }, [detail, scope, treeStyles]);\n\n if (result.status === \"not-found\") return {\n name: null,\n title: \"Genre not found\",\n content: <p className=\"text-[var(--color-text-muted)]\">This genre does not exist.</p>,\n };\n if (result.status === \"error\") return {\n name: null,\n title: \"Genre unavailable\",\n content: <p role=\"alert\" className=\"text-body text-[var(--color-text)]\">This genre could not be loaded.</p>,\n };\n if (!detail || !view) return {\n name: null,\n title: \"Loading genre…\",\n content: <div className=\"flex flex-col gap-3\" aria-busy=\"true\" data-testid=\"genre-detail-panel-skeleton\">\n <Skeleton className=\"h-6 w-2/3\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-3/4\" />\n </div>,\n };\n\n const selectGenre = (nodeId: string) => onSelectGenre(GenreUuidSchema.parse(nodeId));\n const family = (\n <GenreNodeFamily\n node={view.node}\n fill={view.fill}\n textColor={view.textColor}\n parentNode={view.parentNode}\n childNodes={view.childNodes}\n onSelectNode={selectGenre}\n />\n );\n const ancestors = <GenreNodeAncestors ancestorNodes={view.ancestorNodes} onSelectNode={selectGenre} />;\n\n return {\n name: detail.name,\n title: detail.name,\n headerAccent: { background: view.fill, color: view.textColor },\n aside: expanded ? ancestors : undefined,\n content: <>\n <GenreInfoPanelBody<O>\n family={<>{family}{!expanded && ancestors}</>}\n genreUuid={detail.uuid}\n genrePlaylist={hostPlaylist ?? (detail.criteriaPlaylist === null ? null : scope === \"reference\" ? { ...GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist), criteria: CriteriaMinimumSchema.parse(detail) } : { ...detail.criteriaPlaylist, criteria: CriteriaMinimumSchema.parse(detail), tracksCount: detail.tracksCount })}\n catalogue={detail.catalogue}\n wikidataId={detail.wikidataId}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n playback={playback}\n band={{ node: view.node, ...band, shareTarget: band?.shareTarget?.kind === \"genre\" ? { ...band.shareTarget, name: detail.name } : band?.shareTarget }}\n extras={extras}\n />\n {trailing}\n </>,\n };\n}\n\nexport function GenreDetailPanel<O extends CriteriaOverview>({\n genreUuid, scope, getBackendBaseUrl, onClose, onSelectGenre, onZoomIn,\n shareUrl, shareTarget, collapsed, expanded, onExpandedChange, edgeTab, extras, titleInSearch,\n}: GenreDetailPanelProps<O>) {\n const panel = useGenreDetailContent({\n genreUuid, scope, getBackendBaseUrl, onSelectGenre, extras, expanded,\n band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : undefined },\n });\n return (\n <DetailPanel side=\"left\" title={panel.title} headerAccent={panel.headerAccent}\n onClose={onClose} collapsed={collapsed} expanded={expanded}\n onExpandedChange={onExpandedChange} edgeTab={edgeTab} aside={panel.aside} titleInSearch={titleInSearch}\n headerActions={onExpandedChange ? <IconButton aria-label={expanded ? \"Shrink panel\" : \"Extend panel\"} onClick={() => onExpandedChange(!expanded)}>\n {expanded ? <Minimize2 aria-hidden=\"true\" className=\"h-4 w-4\" /> : <Maximize2 aria-hidden=\"true\" className=\"h-4 w-4\" />}\n </IconButton> : undefined}\n >\n {panel.content}\n </DetailPanel>\n );\n}\n","\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport {\n defaultGenreMusicSelection,\n GenreCatalogueCountsSchema,\n type GenreCatalogueCounts,\n type GenrePlaylistSummary,\n type CriteriaOverview,\n type CriteriaMinimum,\n type CriteriaPlaylistMinimum,\n type GenreUuid,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\n\nimport GenreActionBand from \"./GenreActionBand\";\nimport GenrePlayActions from \"./GenrePlayActions\";\nimport { GenreDetailExtras, type GenreDetailExtrasProps } from \"./GenreDetailExtras\";\nimport type { GenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\n\n/** What the action band reads of a genre's playlist: enough to play it and to know whether it can be. */\nexport type PlayableGenrePlaylist = ((CriteriaPlaylistMinimum & { tracksCount: number }) | GenrePlaylistSummary) & { criteria?: CriteriaMinimum | null };\n\ntype GenreNodeActionBandProps = Omit<ComponentProps<typeof GenreActionBand>, \"playActions\"> & {\n genrePlaylist: PlayableGenrePlaylist;\n playback: GenrePlaylistPlayback;\n};\n\nexport function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }: GenreNodeActionBandProps) {\n return <GenreActionBand {...bandProps} playActions={<GenrePlayActions genrePlaylist={genrePlaylist} playback={playback} />} />;\n}\n\nexport type GenreInfoPanelBodyProps<O extends CriteriaOverview> = {\n /** genre-tree-view's toolbar section, rendered first. */\n toolbar?: ReactNode;\n family: ReactNode;\n genreUuid: GenreUuid;\n catalogue?: GenreCatalogueCounts;\n genrePlaylist: PlayableGenrePlaylist | null;\n wikidataId?: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n playback: GenrePlaylistPlayback;\n /** Action band props other than play, which the body derives from `playback`. */\n band: Omit<GenreNodeActionBandProps, \"genrePlaylist\" | \"playback\">;\n extras?: Omit<\n GenreDetailExtrasProps<O>,\n \"family\" | \"genreUuid\" | \"genreName\" | \"genrePlaylist\" | \"wikidataId\" | \"scope\" | \"getBackendBaseUrl\"\n >;\n};\n\n/** The body of a genre's info panel: action band, then the genre's overview, family and tracks.\n * Shared by the tree's panel and the standalone GenreDetailPanel. */\nexport function GenreInfoPanelBody<O extends CriteriaOverview>({\n toolbar,\n family,\n genreUuid,\n genrePlaylist,\n catalogue,\n wikidataId,\n scope,\n getBackendBaseUrl,\n playback,\n band,\n extras,\n}: GenreInfoPanelBodyProps<O>) {\n const summary = scope === \"reference\" ? GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : undefined;\n const selection = summary ? defaultGenreMusicSelection(summary) : undefined;\n return (\n <>\n {toolbar}\n {genrePlaylist ? <GenreNodeActionBand {...band} genrePlaylist={genrePlaylist} playback={playback} /> : <GenreActionBand {...band} />}\n <GenreDetailExtras<O>\n {...extras}\n key={genreUuid}\n family={family}\n genreUuid={genreUuid}\n genrePlaylist={genrePlaylist}\n genreName={band.node.name}\n selection={selection}\n wikidataId={wikidataId}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n />\n </>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { ArrowLeftRight, MoveUpRight, Pencil, Plus, ZoomIn } from \"lucide-react\";\nimport { ActionBand, ActionButton, PanelBleed } from \"@behindthemusictree/ui\";\nimport type {\n GenreTreeAction,\n GenreTreeNode,\n} from \"@behindthemusictree/genre-tree-view\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport ShareActionButton from \"./ShareActionButton\";\n\nexport type GenreActionBandProps = {\n node: GenreTreeNode;\n /** Play buttons, shown first. */\n playActions?: ReactNode;\n /** When set, shows the \"Zoom in\" action. */\n onZoomIn?: () => void;\n /** When set, shows the \"Add\" (sub-genre) action. */\n onAddChild?: () => void;\n /** When set, shows the \"Rename\" action. */\n onRename?: () => void;\n /** When set, shows the \"Parent\" (change parent) action. */\n onChangeParent?: () => void;\n side?: \"core\" | \"pop\";\n /** When set, shows the \"Make pop\" / \"Make core\" action. */\n onToggleSide?: () => void;\n /** When set, disables the side toggle and explains why in its tooltip. */\n toggleSideDisabledReason?: string;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n shareTarget?: GenreTreeShareTarget;\n shareUrl?: string;\n};\n\ntype BandItem = {\n key: string;\n label: string;\n icon: ReactNode;\n onClick: (event: React.MouseEvent) => void;\n disabled?: boolean;\n title?: string;\n};\n\nexport default function GenreActionBand({\n node,\n playActions,\n onZoomIn,\n onAddChild,\n onRename,\n onChangeParent,\n side,\n onToggleSide,\n toggleSideDisabledReason,\n additionalActions,\n shareTarget,\n shareUrl,\n}: GenreActionBandProps) {\n const items: BandItem[] = [];\n const adminItems: BandItem[] = [];\n if (onZoomIn) {\n items.push({\n key: \"zoom-in\",\n label: \"Focus\",\n icon: <ZoomIn aria-hidden=\"true\" className=\"w-5 h-5\" />,\n onClick: onZoomIn,\n });\n }\n if (onAddChild) {\n adminItems.push({ key: \"add-child\", label: \"Add\", icon: <Plus aria-hidden=\"true\" className=\"w-5 h-5\" />, onClick: onAddChild });\n }\n if (onRename) {\n adminItems.push({ key: \"rename\", label: \"Rename\", icon: <Pencil aria-hidden=\"true\" className=\"w-5 h-5\" />, onClick: onRename });\n }\n if (onChangeParent) {\n adminItems.push({ key: \"change-parent\", label: \"Parent\", icon: <MoveUpRight aria-hidden=\"true\" className=\"w-5 h-5\" />, onClick: onChangeParent });\n }\n if (onToggleSide) {\n adminItems.push({\n key: \"toggle-side\",\n label: side === \"pop\" ? \"Make core\" : \"Make pop\",\n icon: <ArrowLeftRight aria-hidden=\"true\" className=\"w-5 h-5\" />,\n onClick: onToggleSide,\n disabled: !!toggleSideDisabledReason,\n title: toggleSideDisabledReason,\n });\n }\n for (const action of additionalActions?.(node) ?? []) {\n items.push({\n key: action.key,\n label: action.label(node),\n icon: action.icon(node),\n onClick: (event) => action.onClick(event, node),\n disabled: action.enabled ? !action.enabled(node) : false,\n });\n }\n const renderItems = (list: BandItem[]) =>\n list.map((item) => (\n <ActionButton key={item.key} icon={item.icon} label={item.label} disabled={item.disabled} title={item.title} onClick={item.onClick} />\n ));\n\n if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;\n\n return (\n <PanelBleed>\n <ActionBand\n className=\"genre-action-band\"\n section={{ title: \"Admin\", label: \"Admin actions\", children: renderItems(adminItems) }}\n >\n {playActions}\n {renderItems(items)}\n {shareTarget && shareUrl && <ShareActionButton target={shareTarget} url={shareUrl} />}\n </ActionBand>\n </PanelBleed>\n );\n}\n","\"use client\";\n\nimport { Share2 } from \"lucide-react\";\nimport { ActionButton } from \"@behindthemusictree/ui\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport SharePopup from \"./SharePopup\";\n\ntype ShareActionButtonProps = {\n target: GenreTreeShareTarget;\n url: string;\n};\n\nexport default function ShareActionButton({ target, url }: ShareActionButtonProps) {\n const { showPopup, hidePopup } = usePopup();\n\n const openSharePopup = () => {\n showPopup(<SharePopup target={target} url={url} onClose={hidePopup} />);\n };\n\n return (\n <ActionButton\n icon={<Share2 aria-hidden=\"true\" className=\"w-5 h-5\" />}\n label=\"Share\"\n aria-label={`Share ${target.name}`}\n title={`Share ${target.name}`}\n onClick={openSharePopup}\n />\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { Link2, Share2 } from \"lucide-react\";\nimport { FaWhatsapp } from \"react-icons/fa\";\nimport { SiGmail } from \"react-icons/si\";\nimport BasePopup from \"../popup/BasePopup\";\nimport Toast from \"../popup/Toast\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport ShareDestinationButton from \"./ShareDestinationButton\";\nimport SharePreviewCard from \"./SharePreviewCard\";\n\ntype SharePopupProps = {\n target: GenreTreeShareTarget;\n url: string;\n onClose: () => void;\n};\n\ntype CopyStatus = \"idle\" | \"failed\";\n\nfunction resolveAbsoluteUrl(url: string): string | undefined {\n try {\n const parsed = new URL(url, window.location.href);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\" ? parsed.href : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function copyText(text: string): Promise<boolean> {\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // Use the legacy copy path when clipboard access is denied or unavailable.\n }\n\n const input = document.createElement(\"textarea\");\n input.value = text;\n input.setAttribute(\"readonly\", \"\");\n input.style.position = \"fixed\";\n input.style.opacity = \"0\";\n document.body.append(input);\n input.select();\n\n try {\n return document.execCommand(\"copy\");\n } catch {\n return false;\n } finally {\n input.remove();\n }\n}\n\nexport default function SharePopup({ target, url, onClose }: SharePopupProps) {\n const [absoluteUrl, setAbsoluteUrl] = useState(url);\n const [copyStatus, setCopyStatus] = useState<CopyStatus>(\"idle\");\n const [canUseNativeShare, setCanUseNativeShare] = useState(false);\n const [shareError, setShareError] = useState<string | null>(null);\n const [toastId, setToastId] = useState(0);\n\n useEffect(() => {\n setAbsoluteUrl(resolveAbsoluteUrl(url) ?? \"\");\n setCopyStatus(\"idle\");\n setShareError(null);\n }, [url]);\n\n useEffect(() => {\n setCanUseNativeShare(typeof navigator !== \"undefined\" && typeof navigator.share === \"function\");\n }, []);\n\n const destinationUrls = useMemo(() => {\n if (!absoluteUrl) return null;\n const message = `${target.name} — ${absoluteUrl}`;\n return {\n whatsapp: `https://wa.me/?text=${encodeURIComponent(message)}`,\n gmail: `https://mail.google.com/mail/?view=cm&fs=1&su=${encodeURIComponent(`Share: ${target.name}`)}&body=${encodeURIComponent(message)}`,\n };\n }, [absoluteUrl, target.name]);\n\n const handleCopy = async () => {\n if (!absoluteUrl) {\n setCopyStatus(\"failed\");\n return;\n }\n setShareError(null);\n const copied = await copyText(absoluteUrl);\n setCopyStatus(copied ? \"idle\" : \"failed\");\n if (copied) setToastId((id) => id + 1);\n };\n\n const dismissToast = useCallback(() => setToastId(0), []);\n\n const handleNativeShare = async () => {\n if (!absoluteUrl || !navigator.share) return;\n setShareError(null);\n try {\n await navigator.share({ title: target.name, url: absoluteUrl });\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") return;\n setShareError(\"Could not open the share options.\");\n }\n };\n\n return (\n <>\n <BasePopup\n title=\"Share\"\n onClose={onClose}\n isDismissable\n trapFocus\n closeOnEscape\n closeOnBackdrop\n className=\"!w-full !max-w-[28rem] overflow-hidden !rounded-[2rem] !bg-[var(--color-surface)] shadow-2xl\"\n overlayClassName=\"!bg-black/50 p-4 backdrop-blur-[2px]\"\n titleClassName=\"!rounded-none !bg-transparent !px-6 !pb-2 !pt-6\"\n titleTextClassName=\"!text-xl !font-semibold !text-[var(--color-text)]\"\n closeButtonClassName=\"!h-10 !w-10 !rounded-none !border-0 !bg-transparent !p-0 !text-[var(--color-text)] hover:!bg-transparent hover:!text-[var(--color-text)]\"\n contentClassName=\"!rounded-none !bg-transparent !px-6 !pb-6 !pt-2\"\n >\n <div className=\"flex flex-col gap-4\">\n <SharePreviewCard target={target} url={absoluteUrl || url} />\n <div className=\"grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4\">\n <ShareDestinationButton\n label=\"Copy Link\"\n icon={<Link2 aria-hidden=\"true\" className=\"h-6 w-6\" />}\n onClick={() => void handleCopy()}\n ariaLabel=\"Copy link\"\n disabled={!absoluteUrl}\n />\n <ShareDestinationButton\n label=\"WhatsApp\"\n icon={<FaWhatsapp aria-hidden=\"true\" className=\"h-9 w-9 text-[#25D366]\" />}\n href={destinationUrls?.whatsapp}\n ariaLabel={`Share ${target.name} via WhatsApp`}\n disabled={!absoluteUrl}\n />\n <ShareDestinationButton\n label=\"Gmail\"\n icon={<SiGmail aria-hidden=\"true\" className=\"h-8 w-8 text-[#EA4335]\" />}\n href={destinationUrls?.gmail}\n ariaLabel={`Email ${target.name} with Gmail`}\n disabled={!absoluteUrl}\n />\n {canUseNativeShare && (\n <ShareDestinationButton\n label=\"More\"\n icon={<Share2 aria-hidden=\"true\" className=\"h-6 w-6\" />}\n onClick={() => void handleNativeShare()}\n ariaLabel=\"More sharing options\"\n disabled={!absoluteUrl}\n />\n )}\n </div>\n {copyStatus === \"failed\" && (\n <p role=\"alert\" className=\"text-center text-body text-[var(--color-red-500)]\">\n Could not copy the link.\n </p>\n )}\n {shareError && (\n <p role=\"alert\" className=\"text-center text-body text-[var(--color-red-500)]\">\n {shareError}\n </p>\n )}\n </div>\n </BasePopup>\n {toastId > 0 && <Toast key={toastId} message=\"Link copied\" onClose={dismissToast} />}\n </>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nexport type ShareDestinationButtonProps = {\n label: string;\n icon: ReactNode;\n href?: string;\n onClick?: () => void;\n disabled?: boolean;\n ariaLabel: string;\n};\n\nconst className =\n \"group flex min-w-0 flex-1 flex-col items-center justify-center gap-1.5 rounded-xl px-2 py-2 text-caption text-[var(--color-text)] transition-colors hover:bg-[var(--color-surface-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50\";\n\nfunction Contents({ icon, label }: Pick<ShareDestinationButtonProps, \"icon\" | \"label\">) {\n return (\n <>\n <span className=\"flex h-12 w-12 items-center justify-center rounded-full bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]\">\n {icon}\n </span>\n <span className=\"max-w-full truncate\">{label}</span>\n </>\n );\n}\n\nexport default function ShareDestinationButton({\n label,\n icon,\n href,\n onClick,\n disabled = false,\n ariaLabel,\n}: ShareDestinationButtonProps) {\n if (href) {\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" aria-label={ariaLabel} className={className}>\n <Contents icon={icon} label={label} />\n </a>\n );\n }\n\n return (\n <button type=\"button\" onClick={onClick} disabled={disabled} aria-label={ariaLabel} className={className}>\n <Contents icon={icon} label={label} />\n </button>\n );\n}\n","\"use client\";\n\nimport { Music, Music2, UserRound } from \"lucide-react\";\nimport type { GenreTreeShareTarget } from \"./share\";\n\ntype SharePreviewCardProps = {\n target: GenreTreeShareTarget;\n url: string;\n};\n\nexport default function SharePreviewCard({ target, url }: SharePreviewCardProps) {\n const Icon = { genre: Music2, artist: UserRound, song: Music }[target.kind];\n const typeLabel = { genre: \"Genre\", artist: \"Artist\", song: \"Song\" }[target.kind];\n\n return (\n <div className=\"rounded-3xl bg-[var(--color-surface-muted)] p-4\">\n <div className=\"flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg\">\n <div className=\"flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]\">\n <Icon aria-hidden=\"true\" className=\"h-10 w-10\" />\n </div>\n <div className=\"flex min-w-0 flex-1 flex-col justify-center gap-1 p-4\">\n <span className=\"text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]\">{typeLabel}</span>\n <span className=\"truncate text-base font-semibold text-[var(--color-text)]\" title={target.name}>\n {target.name}\n </span>\n <span className=\"truncate text-body text-[var(--color-primary)]\" title={url}>\n {url}\n </span>\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { Pause, Play } from \"lucide-react\";\nimport { ActionButton } from \"@behindthemusictree/ui\";\nimport {\n genreMusicCount,\n genreMusicSelectionKey,\n type GenreMusicSelection,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport type { PlayableGenrePlaylist } from \"./GenreInfoPanelBody\";\nimport type { GenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\nimport { RegionGlobeIcon } from \"./RegionGlobeIcon\";\nimport { TreeMarkIcon } from \"./TreeMarkIcon\";\n\ntype PlayIconKind = \"play\" | \"tree\" | \"map\" | \"tree-map\";\ntype PlayOption = { key: string; label: string; icon: PlayIconKind; selection?: GenreMusicSelection; count: number };\n\n/** The play triangle is the same on every button; the scope's glyphs (tree = canonical genres, map = regional genres) stay faint behind it so it reads first. \"All\" joins the left half of the tree and the right half of the globe at the centre. */\nfunction PlayIcon({ kind }: { kind: PlayIconKind }) {\n return (\n <span aria-hidden=\"true\" className=\"relative flex items-center justify-center w-5 h-5\">\n {kind === \"tree\" && <TreeMarkIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35\" />}\n {kind === \"map\" && <RegionGlobeIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35\" />}\n {kind === \"tree-map\" && (\n <>\n <TreeMarkIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]\" />\n <RegionGlobeIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]\" />\n </>\n )}\n <Play className=\"relative w-5 h-5 fill-[var(--color-surface)]\" />\n </span>\n );\n}\n\n/** One option per way to scope a genre's playlist; a plain playlist has a single option. */\nfunction playOptions(playlist: PlayableGenrePlaylist): PlayOption[] {\n if (!(\"genreOnlyTracksCount\" in playlist)) return [{ key: \"all\", label: \"Play\", icon: \"play\", count: playlist.tracksCount }];\n const direct: PlayOption = { key: \"direct\", label: \"Genre\", icon: \"play\", selection: { coverage: \"genreOnly\" }, count: genreMusicCount(playlist, { coverage: \"genreOnly\" }) };\n const scopes = playlist.genreAndSubgenresTracksCount;\n const inclusive = (label: string, icon: PlayIconKind, subgenres: \"canonical\" | \"regional\" | \"all\"): PlayOption => {\n const selection: GenreMusicSelection = { coverage: \"genreAndSubgenres\", subgenres };\n return { key: subgenres, label, icon, selection, count: genreMusicCount(playlist, selection) };\n };\n return \"canonical\" in scopes\n ? [direct, inclusive(\"Canonical\", \"tree\", \"canonical\"), inclusive(\"Regional\", \"map\", \"regional\"), inclusive(\"All\", \"tree-map\", \"all\")]\n : [direct, inclusive(\"All\", \"map\", \"all\")];\n}\n\ntype GenrePlayActionsProps = {\n genrePlaylist: PlayableGenrePlaylist;\n playback: GenrePlaylistPlayback;\n};\n\n/** Play buttons for a genre's playlist, each with the number of playable songs it covers; an empty one stays visible but disabled. */\nexport default function GenrePlayActions({ genrePlaylist, playback }: GenrePlayActionsProps) {\n const { isPlaying, setIsPlaying } = usePlayer();\n const options = playOptions(genrePlaylist);\n return (\n <>\n {options.map((option) => {\n const isCurrent =\n playback.playing?.uuid === genrePlaylist.uuid &&\n (option.selection === undefined || playback.playing.selectionKey === \"\" || playback.playing.selectionKey === genreMusicSelectionKey(option.selection).join());\n const playing = isCurrent && isPlaying;\n return (\n <ActionButton\n key={option.key}\n icon={playing ? <Pause aria-hidden=\"true\" className=\"w-5 h-5\" /> : <PlayIcon kind={option.icon} />}\n label={playing ? \"Pause\" : option.label}\n caption={String(option.count)}\n disabled={option.count === 0}\n title={option.count === 0 ? \"No playable songs\" : undefined}\n onClick={() => {\n if (isCurrent) {\n setIsPlaying(!isPlaying);\n return;\n }\n void playback.play(genrePlaylist, option.selection);\n }}\n />\n );\n })}\n </>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { REGION_GLOBES, REGION_GLOBE_PATHS } from \"./regionGlobePaths\";\n\nconst ROTATION_INTERVAL_MS = 3000;\n\nexport function RegionGlobeIcon({ className }: { className?: string }) {\n const [index, setIndex] = useState(0);\n\n useEffect(() => {\n const reducedMotion = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n let timer: ReturnType<typeof setInterval> | undefined;\n const sync = () => {\n clearInterval(timer);\n timer = reducedMotion.matches\n ? undefined\n : setInterval(() => setIndex((i) => (i + 1) % REGION_GLOBES.length), ROTATION_INTERVAL_MS);\n };\n sync();\n reducedMotion.addEventListener(\"change\", sync);\n return () => {\n reducedMotion.removeEventListener(\"change\", sync);\n clearInterval(timer);\n };\n }, []);\n\n return (\n <svg viewBox=\"0 0 512 512\" fill=\"currentColor\" className={className} aria-hidden>\n <path data-testid=\"region-globe-path\" d={REGION_GLOBE_PATHS[REGION_GLOBES[index]]} />\n </svg>\n );\n}\n","// Globe silhouettes (512x512 viewBox, SVG Repo) as raw path data so they inherit `currentColor`.\nexport const REGION_GLOBE_PATHS = {\n africa: \"M491.879,156.348c-19.45-45.96-51.89-85.017-92.734-112.614C358.3,16.13,308.964-0.008,256.004,0 c-35.306,0-69.02,7.163-99.654,20.122c-45.961,19.45-85.017,51.89-112.614,92.734C16.13,153.701-0.008,203.036,0,255.996 c0,35.306,7.163,69.02,20.122,99.654c19.45,45.961,51.882,85.017,92.735,112.614c40.844,27.605,90.18,43.743,143.147,43.735 c35.299,0,69.012-7.163,99.648-20.121c45.96-19.45,85.017-51.882,112.614-92.735c27.604-40.844,43.742-90.18,43.734-143.147 C512,220.698,504.837,186.984,491.879,156.348z M241.412,128.135c3.914-1.382,10.421,3.07,8.843,7.272 c-2.624,6.983,6.491,10.436,9.49,14.474c2.624,3.522,7.585,14.708-3.148,12.567c-5.094-1.015-6.866,5.234-13.623,1.313 c1.672-2.382,8.382-17.825,3.312-17.583C243.202,146.327,238.367,131.188,241.412,128.135z M233.812,142.281 C231.43,142.96,235.648,141.75,233.812,142.281c8.499-2.437,8.859,11.693,4.882,14.872c-8.303,6.617-8.654-0.328-7.241-5.96 C232.086,148.71,225.009,144.804,233.812,142.281z M48.445,168.331c5.914-13.966,13.224-27.199,21.708-39.572 c3.796-0.343,6.022-2.077,11.201-6.788c4.898,5.999,9.787,11.998,14.693,17.997c1.5,1.836-3.25,4.109-0.938,6.194 c2.921,2.632,4.999,2.75,8.053-0.875c2.008,3.632,4.007,7.272,6.015,10.905c-6.03,2.484-11.014,5.296-17.52,5.171 c-10.319-0.218-15.404-1.18-23.465,5.725c3.374,5.32,7.108,1.96,11.654,0c-2.07,6.093,0.914,14.842,7.897,15.802 c-3.078,2.96-6.163,5.913-9.233,8.874c-1.413,1.359-5.233-3.586-0.921-6.616c-1.57-1.203-4.835-2.562-6.764-3.015 c-0.618,7.194-7.491,2.984-10.53,7.522c-3.312,4.937,3.132,8.022-4.078,10.085c-12.084,3.452-8.655,15.88-17.872,23.019 c-0.952,0.742-3.358,2.203-5.678,3.835C35.322,206.184,40.712,186.641,48.445,168.331z M73.246,276.415 c-0.664-0.383-1.336-0.774-2.008-1.164c-0.468-2.203,5.586-1.289,6.374-0.657C79.464,276.071,73.745,276.321,73.246,276.415z M50.687,273.158c0.961,0.328,1.804,0.171,2.539-0.477c-0.938-0.758-1.945-1.414-3.008-1.96 c-0.875-3.484,18.575,2.672,15.818,4.226c-2,1.133-19.754,1.282-18.84-0.578c0.89-1.116,2.062-1.523,3.484-1.21 C49.5,272.712,50.203,272.978,50.687,273.158z M30.846,260.792c7.421,2.101,14.67,5.077,15.826,5.842 c0.305,0.211-2.733,1.437-1.758,1.765c0.985,0.227,1.906,0.586,2.796,1.055c0.875,0.726-12.068,3.663-11.31,0.695 c0.64-0.828,1.367-1.578,2.172-2.265c-0.149,0.203-3.766-1.781-7.656-3.609C30.877,263.12,30.877,261.948,30.846,260.792z M34.893,273.915c1.336-0.274,9.084,1.78,5.686,3.507c-1.148-0.164-2.296-0.336-3.437-0.508 C34.838,276.477,34.088,275.477,34.893,273.915z M167.386,365.564c-4.898,5.21-4.71,7.397-5.366,13.959 c-0.867,8.631-1.936,25.558-11.646,26.207c-15.982,1.062-20.544,14.216-25.082,26.69c-0.718,2-1.531,3.726-2.398,5.265 c-20.926-15.364-39.134-34.228-53.678-55.764c-15.63-23.152-27.042-49.336-33.213-77.502c2.265,1.031,3.171,3.312,3.179,5.663 c0,0.023,0,0.054,0,0.086c0.141-0.187,0.258-0.382,0.43-0.562c1.555-1.952,13.935-20.379,12.92-7.843 c6.999,1.445,6.038-3.921,11.154-4.772c5.499-0.914,6.788,7.108,12.201,5.39c9.498-3.023,10.186-1.555,15.411,6.288 c5.366,8.046,18.419,4.75,25.636,9.819c5.812,4.085,6.866,8.779,7.702,15.614c0.344,2.858,11.78,3.25,14.466,3.25 c2.867,0,2.429,4.062,3.655,5.6c1,1.258,5.07,0.797,6.374,0.968c6.592,0.829,14.076,2.632,19.466,6.687 C174.776,355.253,171.729,360.932,167.386,365.564z M195.304,92.75c1.585-0.336,4.342,2.726,5.248,2.125 c3.203-2.149,2.492-2.289,7.171-2.554c1.274-0.07,20.646,1.429,15.357,6.74c-0.007,0.008-0.007,0.008-0.007,0.008 c0,0.008,0,0.008-0.008,0.008c-7.452,7.436-13.256,4.96-21.988,4.96C197.318,104.037,187.977,94.265,195.304,92.75z M415.758,398.574c-3.179,10.991-2.187,13.771-12.842,17.474c-3.343-10.388-2.257-16.716-2.257-27.448 c0-0.367,14.552-13.873,16.169-15.802C421.984,382.646,418.766,388.177,415.758,398.574z M481.068,264.502 c-2.241-2.828-4.249-6.178-6.327-8.264c-4.491-4.491-16.732-0.938-23.738-1.882c-6.179-0.828-7.726,0.218-9.905-5.586 c-1.156-3.085-5.343,0.203-8.21,0.477c-8.694,0.82-12.56-13.334-20.575-8.803c2.578,4.038,10.365,16.24,13.584,17.31 c6.514,2.172,4.96-6.835,12.74-4.522c-0.618,2.366,0.281,5.155-0.375,7.514c22.738-5.748,3.14,23.129-6.905,20.981 c-2.75-0.594-1.695,3.5-4.601,4.343c-4.452,1.304-8.905,2.601-13.365,3.898c-5.648,1.648-10.654,5.758-13.842,0.297 c-7.428-12.724-12.263-28.401-21.621-38.658c-1.616-1.773-4.421-4.444-6.452-7.373c0.078,0.234,0.148,0.484,0.234,0.718 c-1.804-1.313-4.476-1.469-6.397-2.624c-2.321,6.444,6.491,15.021,10.177,20.285c4.75,6.781,5.882,16.154,10.882,22.575 c2.148,2.765,6.022,4.139,7.974,7.076c1.657,2.484,5.156,10.655,7.82,11.725c4.077,1.64,17.302-4.468,21.808-5.64 c-2.398,5.765-7.678,25.332-13.224,27.816c-10.6,4.75-13.278,9.03-20.113,18.677c-0.539,0.75-5.554,6.256-5.617,6.007 c1.266,4.944,2.531,9.888,3.789,14.832c0.936,3.664,2.336,20.138-0.485,20.966c-13.006,3.859-13.966,7.514-14.286,20.708 c-0.133,5.429-6.46,13.091-10.506,17.739c-5.936,6.819-10.545,15.99-19.715,17.263c-8.491,1.179-16.997,2.28-25.512,3.39 c0-6.881,0.633-9.397-3.694-14.583c-5.085-6.101-5.827-7.859-6.843-15.74c-1.141-8.905-11.92-21.231-9.428-29.058 c4.906-15.381,3.523-20.887-0.562-36.728c-1.226-4.773-7.186-7.343-8.413-11.803c-0.96-3.46,1.126-11.951,1.126-15.794 c-7.382,0.616-8.663,1.046-14.389-3.632c-4.694-3.835-9.194-0.352-14.747,1.445c-4.609,1.492-11.616-0.437-16.427-0.773 c-3.867-0.274-9.585,4.093-13.1,2.96c-7.413-2.39-18.2-21.575-23.309-27.644c-4.804-5.686-1.867-19.145-2.226-26.94 c-0.484-10.373,12.74-20.262,20.184-24.98c2.047-1.297,3.109-8.397,5.898-11.1c3.953-3.835,6.499-8.123,12.045-8.42 c9.764-0.516,20.903-5.335,31.026-6.764c5.632-0.797,11.272-1.594,16.912-2.39c2.328-0.329,6.475,8.389,0.758,10.1 c3.39,6.709,14.833,4.632,15.81,7.561c1.929,5.788,9.373,4.906,15.029,5.968c-0.782-14.225,10.88-3.976,17.746-2.047 c5.202,1.452,8.679-1.695,13.842-1.703c4.288-0.008,9.326,2.07,13.537,3.008c0.007,0.054,0.023,0.094,0.038,0.148 c0.07-0.328,0.157-0.656,0.29-0.984c2.812-7.03,4.178-11.21,4.178-18.724c-4.468,0.531-18.551,4.796-22.176,2.632 c-2.164-1.289-4.25-8.014-5.436-10.248c-2.062-3.906,0.687-3.859,4.265-6.194c12.318-8.03,26.535-2.484,39.892-5.366 c-1-4.85-3.57-7.178-7.14-10.154c-5.35-4.453-4.273-5.054-3.014-12.029c-3.508,1-7.015,2-10.53,3.007 c1.296,1.531,1.336,4.132,2.632,5.639c-8.828,6.148-6.359-5.163-12.404-6.006c-5.39-0.766-6.804,8.154-9.538,11.388 c-3.906,4.64,1.672,8.303-4.562,10.6c-4.351,1.602-7.241,5.577-12.217,3.952c3.664,2.024,5.882,4.976,4.882,9.022 c-1.453-0.798-3.468-0.641-4.882-1.5c0.727,1.984,0.298,4.444,1.125,6.381c-5.984-2.695-11.928-12.521-12.974-18.802 c-0.898-5.374-14.286-12.513-18.989-16.536c-7.577,8.288,13.286,12.63,15.224,19.739c-0.141-0.531-4.022,11.662-4.319,11.842 c-5.242,3.249-4.242-7.679-5.96-9.249c-5.147-4.671-15.669-19.348-21.254-14.825c-7.671,6.218-4.616-1.062-10.818,0.875 c-5.835,1.82-3.156,7.436-6.757,8.514c-9.662,2.898-2.382,5.866-8.155,10.678c-5.717,4.765-6.616,4.75-14.029,4.601 c-14.138-0.266-16.872-3.624-15.458-17.81c1.203-11.959,14.513-7.014,24.355-6.858c3.601,0.062,2.211-9.233,0.297-11.146 c-3.32-3.312-7.819-2.375-10.279-6.89c14.505-2.593,18.176-10.045,29.705-18.051c1.852-1.282,12.811-5.327,12.725-6.499 c-0.211-3.257-2.789-15.615,4.952-14.185c7.217,1.343-3.304,12.146,2.554,12.466c3.296,0.188,12.014,4.523,12.802,3.664 c4.648-5.07,10.162-3.164,16.92-2.992c2.335,0.062,5.46-11.146,6.452-13.513c8.279,8.366,6.725-2.53,5.632-7.522 c3.101,0.117,14.599,1.96,16.552-2.25c3.586-7.71-8.764-4.898-12.224-3.945c-4.085,1.11-11.778,2.039-13.349-4.327 c-0.508-2.085,4.304-12.279,6.272-13.318c5.617-2.976,7.617-5.991,1.946-10.623c-6.327-5.187-6.358,8.061-7.084,8.897 c-6.281,7.217-22.809,10.974-9.023,22.567c-4.382,0.984-6.014,3.179-6.147,7.084c-0.266,7.225,0.266,6.733-6.827,8.046 c-6.726,1.241-7.812-10.577-9.975-16.264c-4.929,5.21-15.006,14.271-19.169,2.258c-3.827-11.084,5.757-14.342,13.224-17.739 c6.351-2.882,12.646-15.802,16.95-21.387c2.531-3.273,0.43-5.117,4.234-8.257c3.788-3.116,6.96-3.483,11.826-4.577 c4.093-0.922,7.178-5.562,11.177-5.648c5.75-0.108,11.522,0.321,17.263,0.594c7.007,0.344,1.75,3.414,5.242,4.554 c5.218,1.71,10.428,3.421,15.638,5.124c5.718,1.875,17.763,6.96,13.521,12.795c-4.562,6.264-16.325-1.461-20.715-3.812 c-3.57,6.374,3.179,5.132,6.397,8.647c0.828,0.906-1.578,4.734-0.757,5.64c1.32,1.446,4.35,2.515,6.03,3.492 c5.108,2.953,3.077-8.1,1.125-6.124c2.726-2.765,4.663-2.765,9.014,0c0.641-5.827,7.257-7.913,12.037-5.265 c0.078-2.883,0.149-5.781,0.227-8.671c16.176,13.545,30.432,29.308,42.274,46.836c24.293,35.963,38.454,79.213,38.462,125.916 C481.248,258.847,481.177,261.683,481.068,264.502z M50.687,273.158c0,0,0,0-0.008,0C51.257,273.376,51.023,273.282,50.687,273.158z M432.998,199.451c0.226,1.078-5.476-4.804-5.928-5.444c-1.914-2.696-3.812-5.39-5.726-8.093 c5.89-0.257,7.695-4.014,7.523-9.389c-11.131,0-26.02,5.89-15.435,18.153c1.469,1.696,5.991,5.242,6.406,7.405 c0.305,1.578-4.391,2.858-3.906,5.32c1.586,7.904,3.742,7.17,11.428,9.725c1.952-0.141,4.163-1.555,6.022-2.25 c-1.304-2.819-4.178-6.725-4.514-9.787C428.764,204.247,433.756,203.106,432.998,199.451z\",\n americas: \"M491.875,156.347c-19.446-45.958-51.889-85.019-92.736-112.613C358.3,16.13,308.962-0.008,255.996,0 c-35.305,0-69.016,7.168-99.65,20.124C110.381,39.571,71.321,72.006,43.725,112.86C16.122,153.692-0.016,203.03,0,255.996 c-0.008,35.313,7.16,69.016,20.125,99.658c19.438,45.958,51.881,85.018,92.728,112.613C153.692,495.87,203.03,512.008,255.996,512 c35.305,0,69.016-7.168,99.649-20.125c45.966-19.446,85.018-51.882,112.621-92.736C495.87,358.308,512,308.97,512,255.996 C512,220.691,504.832,186.988,491.875,156.347z M374.27,351.228c-8.571,14.798-1.69,35.384-12.262,48.78 c-10.947,13.514-16.513,10.221-24.295,28.328c-0.853,2.36-14.742,31.917-18.211,23.122c3.054,7.854-0.383,15.66-10.357,16.274 c-7.95,0.47-2.233,5.071-4.704,8.252c-9.863,2.17-19.965,3.708-30.274,4.521c-6.928-25.299-10.74-54.6-10.565-62.972 c0.638-32.484-6.609-19.327-23.609-43.342c-11.616-16.513-21.91-34.803-21.304-55.733c-0.088,3.74,23.329-53.086,6.426-42.25 c-20.532,13.172-24.311-14.567-44.092-17.158c-10.102-1.339-7.16-11.768-18.49-9.982c-10.174,1.594-21.735-11.904-29.277-16.991 c-4.951-3.572-13.578-51.619-20.842-50.933c-10.373,0.383,7.598,33.049,3.835,34.142c-7.742,1.451-21.313-46.093-21.057-50.008 c0.39-12.63-0.83-19.75,7.527-30.251c3.245-4.226,21.718-20.475,19.773-26.304c-3.308-10.166-1.602-22.022-6.905-28.831 c4.681-3.739,9.504-7.311,14.487-10.677c10.31-6.968,21.249-13.076,32.675-18.282c1.332-0.04,2.663-0.096,3.97-0.239 c10.206-0.997,20.627-4.959,30.992-3.388c13.666,2.008,28.488,7.893,42.88,6.769c13.251-0.933,50.638-12.949,62-3.254 c5.015,4.306-56.443,21.72-58.396,30.043c-0.997,5.422,16.002,4.944,17.469,5.079c17.087,1.403-4.241,15.452,6.252,18.481 c16.114,3.891,27.738-56.338,41.205-24.844c5.502,13.06,24.406-8.547,26.543,7.566c2.153,16.951,18.426,22.684-11.506,24.885 c-28.073,2.28-4.864,14.726-23.186,22.811c-17.525,7.718-33.552,11.107-46.46,26.966c-14.559,17.987-15.954,17.389-21.671,40.408 c-3.15,12.565-19.678-8.842-13.371-16.696c-2.185,2.694-21.544-6.1-23.466-1.587c-3.755,8.706-13.961,4.035-21.982,9.369 c-10.142,6.706-20.077,28.44-9.927,38.63c8.125,8.101,36.095-17.884,37.618-9.01c1.196,6.786-9.919,11.601-8.706,18.387 c1.746,9.823,18.872-2.815,18.864,4.816c0.008,4.895-0.805,25.355,14.272,20.236c8.125-2.774,8.93,3.046,14.009,1.826 c6.96-1.683,10.07-10.963,18.275-9.752c9.766,1.427,20.714,6.371,30.074,9.13c15.213,4.504,14.535,17.214,31.463,19.821 c16.911,2.663,10.15,18.323,8.068,27.197C329.007,322.58,399.107,310.772,374.27,351.228z M440.711,127.133 c0.686,0.981,1.403,1.954,2.066,2.95c4.01,5.916,7.71,12.064,11.138,18.378c-1.443,0.494-2.806,0.893-3.851,1.012 c-4.417,0.558-11.585-3.301-12.685-4.959C436.493,143.191,439.468,131.726,440.711,127.133z M481.223,257.232 c-1.252-0.702-2.615-1.077-4.138-0.766c-5.518,1.1-26.471,6.618-34.189,5.509c-7.726-1.108-31.981-24.262-31.981-29.779 c0-5.51,1.101-26.471,3.301-29.78c2.209-3.309,14.336-18.426,18.753-25.036c4.409-6.625,11.027-15.436,16.544-16.544 c1.715-0.343,5.375-1.012,9.824-1.834c14.032,29.374,21.902,62.231,21.91,96.994C481.247,256.411,481.223,256.809,481.223,257.232z\",\n asia: \"M491.878,156.348C472.437,110.39,439.989,71.33,399.14,43.731C358.307,16.131,308.964-0.008,256,0 c-35.304,0-69.011,7.167-99.652,20.122C110.39,39.564,71.33,72.011,43.731,112.86C16.131,153.693-0.008,203.036,0,256 c0,35.304,7.167,69.02,20.122,99.653c19.442,45.957,51.889,85.016,92.738,112.616c40.832,27.6,90.176,43.74,143.14,43.731 c35.305,0,69.02-7.166,99.653-20.122c45.957-19.442,85.017-51.889,112.617-92.738c27.6-40.832,43.74-90.176,43.731-143.14 C512,220.697,504.842,186.98,491.878,156.348z M427.814,110.348c0.774,0.915,1.53,1.856,2.294,2.789 c-1.496-0.454-2.991-0.908-4.486-1.37C426.353,111.297,427.084,110.819,427.814,110.348z M382.832,101.182 C387.142,100.754,380.446,101.434,382.832,101.182c-1.798-0.126-3.159-0.858-4.066-2.177 C384.579,95.217,388.747,100.585,382.832,101.182z M290.917,81.127c1.613,4.142-9.956,0.277-11.216-0.336 c-0.739-0.739-1.294-1.58-1.663-2.52C278.021,79.203,290.388,79.749,290.917,81.127z M258.79,75.406 c2.823,0.958,14.022-1.572,14.383,1.722c0.673,6.049-3.99,0.058-4.956,0.058c-2.622,0,1.21,2.78,1.31,2.923 c-0.656-0.957-8.461-0.857-10.107-0.462C254.656,88.352,241.675,69.592,258.79,75.406z M271.711,87.026 c-3.108,1.142-8.443,0.168-11.754,0.168C253.808,85.58,276.718,85.194,271.711,87.026z M79.236,313.19 C79.06,315.812,79.346,311.544,79.236,313.19c0.042-0.663,1.126-5.755,2.084-6.049c1.513-0.453,4.613,6.999,4.487,8.041 C85.11,321.206,78.892,318.148,79.236,313.19z M136.15,339.169c-3.252-3.983-5.192-8.461-8.284-12.528 c-0.63-0.84-11.031-6.754-9.058-7.796c4.243-2.21,39.505,18.517,37.934,21.676c-0.152,0.303-7.889-6.797-9.847-5.52 c-1.302,0.848,2.689,3.932,2.689,5.419c2.016,1.033,7.149,8.646,2.932,8.872C147.862,349.545,138.872,342.512,136.15,339.169z M154.894,340.546c0.21,1.37-3.646-1.185-3.873-1.277C151.777,337.884,154.718,339.412,154.894,340.546z M151.92,353.208 c-3.898-2.487,12.569-0.554,13.459-0.487c3.252,0.243,11.418,0.076,13.552,3.974C179.569,357.862,155.574,355.544,151.92,353.208 C154.356,354.77,150.122,352.066,151.92,353.208z M188.686,317.644c4.125-4.201,8.839,3.235,9.174,2.932 c-2.596,2.369-6.486,6.94-1.252,9.671c3.932,2.058-4.672,3.537-4.672,4.268c0,2.966-4.771,10.795-7.814,12.014 c0.177-0.067-11.913-3.419-12.972-3.722c-2.638-0.764-3.445-8.082-5.058-10.426C166.093,328.036,184.51,321.895,188.686,317.644z M167.53,281.869c1.756-1.328,3.378-1.479,4.848-0.454C173.546,287.801,165.514,282.785,167.53,281.869z M195.718,306.864 c0.009-0.017,0.017-0.025,0.034-0.034c0.067-0.059,0.101-0.084,0.092-0.076c1.05-0.857,3.806-3.302,4.898-3.546 C203.716,302.529,193.676,308.502,195.718,306.864z M201.658,294.278c-0.563-3.353-0.151-3.974,0.093-6.68 c0.428-4.713,5.915-6.772,7.007-1.092c0.193,0.975-5.721,9.88-1.218,9.317c3.612-0.454,6.301-0.622,5.134,3.932 c-1.076-0.714-7.814-4.075-8.637-3.898c-0.798,0.168-3.36,8.746-6.049,7.939C199.162,304.151,201.809,295.95,201.658,294.278z M200.734,269.073c0.084-1.328,2.042-5.125,4.176-4.688c2.461,0.513-0.731,10.141-2.487,9.032c-1.26-1.193-1.823-2.639-1.689-4.335 C200.7,269.678,200.608,271.199,200.734,269.073z M213.479,300.403c0.016-0.008,0.016-0.016,0.034-0.016 c4.797-2.42,3.452,4.218,3.965,4.452C216.831,304.546,213.101,300.613,213.479,300.403z M218.184,308.04 C217.26,307.889,219.276,308.217,218.184,308.04c1.521,0.244,2.269,3.369,2.42,4.378c0.621,4.243,0.546,2.411-2.26,3.52 c-0.765,0.294,0.084,2.747-1.672,2.865c-0.84,0.05-5.436-0.908-3.948-2.672c3.091-3.663-5.663-0.815-5.663-1.134 c0-1.227,1.386-4.075,3.184-3.697C215.504,312.384,215.58,307.62,218.184,308.04z M223.435,335.086 c-1.311-1.748-0.118-6.075,1.159-7.512c-1.016,1.142,2.706,3.058,2.882,2.26C227.081,331.632,223.661,335.388,223.435,335.086z M230.03,343.202c-0.076-0.739-6.041-0.588-6.948-0.73C221.51,342.471,229.593,338.766,230.03,343.202z M223.704,262.839 c-3.907,0.89,0.816-2.747,1.664-2.823C226.518,259.907,223.914,262.554,223.704,262.839z M222.393,355.989 c1.529,3.941-8.503,4.672-9.906,5.008c1.076-0.261,7.284-2.588,7.898-4.26C220.494,356.426,221.612,353.964,222.393,355.989z M200.557,343.369c-2.243,1.227,0.21,5.831-2.16,6.066c-3.503,0.352-1.638-8.755-0.866-11.208 c3.798-11.998,9.352,4.495,12.469-3.47c-0.252,0.647-10.847-2.655-9.091-3.201c0.025-0.008,0.051-0.008,0.076-0.017 c2.89-0.873,12.997-3.184,15.408-2.596c0.571,0.134-6.662,10.132-10.636,9.83c4.798,0.369,2.705,7.419,0.941,9.351 c-0.63,0.689,4.411,2.646,3.722,3.117C207.993,352.914,197.574,345,200.557,343.369z M206.497,356.938 c0.597,0.303-2.731,1.025-3.159,1.109c-1.377,0.47-2.688,0.412-3.932-0.176C198.465,357.115,205.691,356.535,206.497,356.938z M199.297,358.946c-0.647,0.404-1.336,0.404-2.067,0C195.256,357.744,198.348,357.938,199.297,358.946z M205.548,300.05 c0,0,0,0-0.009,0c-0.025-0.025-0.051-0.042-0.076-0.058c0.017,0.008,0.034,0.025,0.058,0.041c-0.235-0.159-2.68-1.814-0.84-2.008 C207.278,297.757,205.582,300.076,205.548,300.05z M208.783,308.284c-2.798,0-3.016-4.05-3.134-5.621 C207.748,296.421,209.429,308.284,208.783,308.284z M209.975,358.132c0.74-0.387,8.208-2.403,7.704-1.613 c-0.471,0.748-8.838,4.604-9.679,2.924C208.228,358.527,208.883,358.09,209.975,358.132z M218.839,343.202c0.008,0,0.017,0,0.017,0 c-0.026,0-0.009,0-0.026,0c-1.142,0.051-1.622-0.328-1.403-1.143c2.445-1.126,3.344,1.303,1.429,1.143 C219.318,343.244,219.091,343.226,218.839,343.202z M209.707,304.738c-0.093-0.042-0.06-0.025-0.009-0.008 c-1.294-0.512-0.109-3.394,1.084-2.118C211.177,303.041,210.454,305.016,209.707,304.738z M212.244,305.528 c-0.084,0.68-0.605,3.453-1.84,3.453c-0.218-0.74-0.218-1.479,0-2.218C210.539,305.629,211.151,305.218,212.244,305.528z M202.355,305.184L202.355,305.184c-0.58,1.168-7.78,9.838-8.839,5.184C193.542,310.486,201.884,306.142,202.355,305.184z M194.903,356.737c-1.512,0.395-2.789,1.294-4.47,0.344C188.719,356.115,194.836,356.737,194.903,356.737z M187.451,356.325 c-0.992,0-0.446-0.656,0.268-0.739C188.442,355.502,188.35,356.325,187.451,356.325z M281.365,457.809 c-5.629,13.039-11.771-7.864-10.998-7.62C277.752,452.726,286.145,446.736,281.365,457.809z M293.849,421.691 c-1.949,5.721-3.814,11.728-7.343,16.845c-4.864,7.049-8.561,3.294-15.064,3.234c-3.723-0.034-2.849,2.866-6.916,1.278 c-2.285-0.899-5.402-1.597-7.444-2.916c2.521,1.63-4.394-9.427-3.764-5.411c-0.344-2.167-2.823-1.084-4.848-1.479 c1.093-1.386,1.042-3.537,2.151-4.915c-2.747-0.067-5.091,1.135-6.814,3.277c-7.738-9.561-14.93-10.452-27.372-7.327 c-2.882,0.723-8.604,5.361-10.208,5.361c-6.537,0-8.041-0.261-12.914,3.596c-3.344,2.646-11.703,0.84-12.678-3.596 c-0.446-2.016,3.218-4.797,3.226-6.89c0.008-1.327-3.84-2.596-4.31-3.94c-0.723-2.108,1-4.596-0.781-6.343 c-0.748-0.731-4.125-3.15-4.243-4.15c-0.151-1.319,2.874-2.731,2.874-4.386c0-2.336,0-4.663,0-6.999 c0-5.284,14.291-6.46,19.962-9.057c6.629-3.025,1.764-4.906,5.881-8.427c1.236-1.05,5.529,1.008,6.822,0 c0.739-0.571-0.218-3.36,0.781-4.478c1.412-1.562,7.796-8.108,8.284-1.874c0.286,3.697-0.067,3.402,3.99,3.402 c3.268,0-0.176-1.604,1.302-2.948c2.244-2.05,5-8.645,7.898-9.511c1.697-0.513,10.183,3.268,12.914,3.277 c-0.95,2.73-1.874,5.478-2.865,8.2c4.267,2.16,12.258,8.788,17.223,5.906c2.318-1.352,3.268-13.014,3.949-15.745 c2.881,4.453,7.83,7.755,9.519,12.09c2.579,6.604,6.864,6.83,10.729,12.233c3.604,5.016,6.906,9.864,9.906,15.199 C297.757,412.423,296.564,413.717,293.849,421.691z M237.466,240.155c1.05,1.444-3.789,8.956-4.907,6.982 c-0.772-1.37-0.982-4.73-1.554-6.428c-0.109-0.319-0.319-0.958,0-0.008C230.064,237.928,236.24,238.475,237.466,240.155z M267.989,202.381c3.991-0.008,4.168,5.125,8.604,3.772c-0.866,0.26,2.478,3.621-2.16,4.486c-2.916,0.529-6.965,3.73-10.166,1.63 c0.428,0.286,0.218,0.151,0.008,0.016c1.95,1.311-3.47,2.412-3.671,0.89C260.604,213.202,270.182,202.372,267.989,202.381z M268.569,177.066c0,0.092,1.604-2.21,2.252-3.176c-0.706,2.824,6.435,16.526,4.335,17.173c-1.31,0.404-3.101-2.134-3.596-1.529 c-2.209,2.697,1.74,6.83,0.479,7.973c0.319-0.286-2.958,0.723-3.772,1.193c0.017,0.152,0.042,0.236,0.067,0.236 c-0.335,0-0.302-0.093-0.067-0.236C268.023,196.458,268.712,178.62,268.569,177.066z M291.959,363.442 c-7.687,1.613-17.484-13.88-21.886-7.05c-3.151,4.89-16.854-2.201-17.409-0.083c0.782-2.992,5.84-0.933,2.579-5.294 c-2.805-3.756-6.351-3.546-10.897-4.201c-3.251-0.47-2.352-2.453-3.772-4.268c-0.874-1.117-1.832,1.958-2.689,1.639 c-0.118-0.042-4.848-6.982-4.848-7.209c5.864-7.688,7.494,2.764,10.771,4.1c6.612,2.697,6.704-4.73,13.098-1.806 c3.251,1.487,27.7,10.418,26.877,12.493c-0.428,0.496-0.949,0.874-1.571,1.118C283.382,354.77,291.144,363.618,291.959,363.442z M239.138,239.726c0-0.009,0-0.009,0-0.017c0.907-2.848,8.679-3.907,7.301-0.756C245.725,240.592,238.088,243.12,239.138,239.726z M261.218,221.948c0.008-0.176,3.126-11.066,4.722-8.15c1.756,3.218,0.95,19.433-2.874,21.769 c-0.991-0.084-1.352-0.597-1.076-1.538c0,2.05-13.325,5.05-13.14,5.234c-2.075-2.151,1.344-3.428-3.756-2.941 c0.075,0-11.309,1.487-7.746-0.546c3.798-2.168,7.074-2.714,11.527-2.798c3.646-0.067,3.319-5.276,5.94-5.511 c1.227-0.109,0.538,3.369,2.748,1.537C260.478,226.586,260.881,225.46,261.218,221.948z M292.53,351.729 c-2,0.488-7.343-2.218-5.478-2.453c-1.646,0.201-0.588,0.067,0.017-0.009c3.285-0.412,7.612-1.697,10.217-1.966 C299.899,347.041,293.539,351.486,292.53,351.729z M299.706,347.142c-0.513-0.538-0.908-1.134-1.16-1.806 C296.354,341.832,303.705,348.604,299.706,347.142z M376.371,386.555c-0.924-0.143-1.252-0.672-0.991-1.58 c0.984-2.823,3.059,1.033,3.386,1.37C377.968,386.412,377.169,386.488,376.371,386.555z M379.958,381.53 c-0.865,0,1.924-3.042,3.588-1.395C385.26,381.824,380.295,381.446,379.958,381.53z M397.502,128.882 c-4.588-0.865-3.108-4.159-6.713-4.462c-4.226-0.353-1.932,5.016-5.713,4c-13.897-3.73-0.63,5.469-4.882,9.612 c0.428-0.412-7.335-1.093-8.712-0.622c-2.815,0.966-6.738,1.622-9.108,3.352c-3.193,2.336-6.385,4.672-9.578,6.999 c-1.68,1.236-3.822-2.016-6.15-0.932c-2.731,1.269-8.78,0.513-10.595,1.697c-1.941,1.277-3.369,7.192-4.318,9.208 c-3.756,8.007-8.108,25.087-19.727,26.222c-0.572-4.79-5.957-24.718,3.73-25.752c7.747-0.84,18.82-12.014,16.728-19.845 c-7.771,0.311-3.847,4.739-7.183,6.235c-6.084,2.722-6.94-3.168-9.074-2.286c-6.377,2.655-6.974,2.454-8.284,8.755 c-0.487,2.336-8.847,0.774-11.107,0.689c-6.436-0.227-22.358-2.588-27.138,0.605c-7.427,4.957-14.854,9.914-22.282,14.871 c3.982,7.579,14.846,2.512,17.224,10.167c1.571,5.023-5.192,14.938-8.914,18.76c-3.664,3.772-7.335,7.545-11.006,11.318 c-3.512,3.612-3.991-0.488-7.352,1.411c-5.218,2.941-5.201,11.897-12.57,12.14c3.117,4.109,3.681,7.016,4.058,11.847 c0.378,4.89-3.243,4.487-8.007,6.192c-0.143-3.016-0.588-6.04,0-9.023c0.849-4.26-4.074-0.336-3.226-4.588 c1.47-7.385-7.906-3.201-11.846-2.134c0.302-2.134-0.412-4.444,0-6.561c-4.067,2.294-8.132,4.595-12.199,6.889 c3.688,3.185,6.284,7.276,11.838,4.587c0.571,4.075-3.126,4.537-6.814,6.562c5.142,3,5.436,9.83,6.948,14.779 c1.932,6.285-2.252,8.41-6.645,13.561c-4.672,5.478-5.655,6.982-12.746,8.931c-3.932,1.092-7.864,2.176-11.796,3.26 c-2,0.554-0.319,3.428-4.117,3.428c-0.982-6.73-8.847-1.386-11.258,1.512c-3.579,4.284,3.159,7.486,6.756,10.998 c9.653,9.436-3.874,15.123-10.931,19.962c-2.563-6.772-10.234-8.67-12.208-14.106c-2.689,9.838-3.285,10.074,4.033,17.568 c5.335,5.469,6.058,9.796,8.175,16.87c-4.31-1.966-9.377-2.907-11.073-7.142c-2.076-5.167-3.621-8.048-7.47-12.267 c-3.965-4.352-4.134-17.256-6.225-23.231c-1.555,1.168-4.201,1.118-5.747,2.294c-1.16-4.436-4.217-16.913-9.687-18.694 c-4.453-1.453-14.241,4.646-17.82,7.267c-4.721,3.47-15.476,8.226-15.636,14.09c-0.268,10.234-0.538,10.998-8.897,17.677 c-8.007-11.67-12.108-21.239-14.359-34.775c-7.662,3.755-11.872-6.578-16.509-10.821c-2.151-1.957-6.16-2.151-10.461-1.966 c-0.092-2.655-0.15-5.318-0.15-7.99c0-31.145,6.301-60.728,17.694-87.672c16.123-38.135,42.504-70.936,75.649-94.922 c2.142-0.05,4.251,0.286,6.326,1.294c4.025,1.966,9.368-4.974,15.392-2.924c-2.142-8.746,18.668-9.174,13.997,0.328 c4.537-1.336,8.486-3.184,13.208-2.487c7.746,1.126,5.578,2.403,4.529,9.368c-0.042,0.261-24.189,8.838-15.812,10.014 c8.108,1.143,15.132-4.327,23.542-3.713c9.687,0.698,14.005,4.89,24.424,5.184c-4.159-9.99,12.728-2.789,17.946-1.638 c-5.78,4.748,5.738,10.158,9.696,13.452c-0.143-7.301,14.871-5.973,21.6-5.629c3.706,0.194,1.983-6.638,6.57-5.839 c6.226,1.084,12.443,2.167,18.668,3.251c5.252,0.916,8.015-0.344,13.148,2.403c3.512,1.882,1.143,6.394,5.948,5.882 c3.42-0.362,11.595-2.806,14.048-0.362c3.655,3.638,1.597,7.814,7.596,9.805c1.352-6.663,12.871-6.612,18.66-4.924 c2.68,0.79,14.972,10.544,10.41-1.311c10.871,2.21,21.734,4.411,32.606,6.621c4.26,0.866,4.352,4.192,7.956,5.848 c2.344,1.076,8.856,0.748,12.2,1.966C413.851,126.9,403.425,130.008,397.502,128.882z M406.693,134.654 c0.176-0.588,0.362-1.176,0.546-1.764c1.429-1.412,9.62-1.546,10.814,0.428C419.136,135.108,407.441,135.293,406.693,134.654z M437.107,168.185c4.974-4.864,9.897-9.754,15.081-14.425c-10.149,0.513-12.468,2.932-14.358-6.562 c-2.151,1.31-4.31,2.621-6.461,3.932c-2.638-3.923-8.838-9.552-2.874-13.778c1.782-1.252,6.008,0.487,7.898-0.656 c1.832-1.1,3.293-6.008,4.31-7.873c-5.176-1.84-5.31,2.723-9.334,2.63c-3.881-0.092-9.258-3.293-12.922-4.596 c3.377-6.99,11.485-5.906,17.013-6.939c2.521,3.318,4.982,6.687,7.326,10.158c6.41,9.494,12.09,19.508,17.022,29.943 C453.406,164.791,445.156,170.715,437.107,168.185z M453.18,278.096c-1.051,0.194-1.673-1.747-0.236-1.747 C454.381,276.349,454.381,277.878,453.18,278.096z M457.011,283.785c-0.47-0.58-0.227-0.278-0.008-0.017 c-2.243-2.739-1.663-6.209,2.403-4.352C461.498,280.356,458.43,285.499,457.011,283.785z M231.005,240.701v0.008C231.055,240.86,231.089,240.945,231.005,240.701z M287.07,349.268c-0.008,0-0.008,0.009-0.017,0.009C287.608,349.2,287.414,349.226,287.07,349.268z\",\n} as const;\n\nexport type RegionGlobe = keyof typeof REGION_GLOBE_PATHS;\n\nexport const REGION_GLOBES: readonly RegionGlobe[] = [\"africa\", \"americas\", \"asia\"];\n","// The Music Tree mark (brand `the-music-tree-mark.svg`, 551x567 viewBox, y-flipped at 0.1 scale) as raw path data so it inherits `currentColor`.\nexport const TREE_MARK_PATH =\n \"M3171 5598 c-5 -13 -5 -24 0 -26 5 -2 9 -16 9 -31 0 -25 -3 -28 -25 -23 l-25 4 0 -116 c0 -64 3 -116 8 -116 10 0 32 51 26 61 -3 5 -1 9 4 9 5 0 15 12 21 28 7 15 26 36 43 47 30 20 88 105 71 105 -4 0 -33 -21 -62 -47 l-54 -47 6 63 c4 35 7 72 7 82 0 10 9 19 23 22 16 3 13 5 -11 6 -25 1 -35 -4 -41 -21z M2893 5485 c8 -76 24 -100 71 -100 l36 0 0 53 c0 58 -15 69 -28 20 -8 -29 -10 -30 -16 -13 -15 43 -42 89 -55 93 -11 4 -13 -6 -8 -53z M2484 5438 c8 -70 49 -169 54 -131 2 12 10 27 18 33 17 15 19 84 3 129 -9 27 -16 31 -46 31 l-36 0 7 -62z M2625 5448 c-7 -22 -24 -121 -31 -179 l-6 -57 -27 11 c-15 5 -32 19 -37 31 -9 21 -88 86 -105 86 -39 0 38 -104 118 -158 17 -12 56 -59 86 -105 30 -45 67 -92 81 -104 14 -13 26 -30 26 -38 0 -13 -9 -11 -45 11 -67 39 -58 10 21 -66 67 -65 96 -110 108 -167 4 -17 13 -34 20 -36 20 -8 66 -186 75 -289 13 -161 -8 -272 -72 -365 -12 -18 -30 -33 -39 -33 -23 0 -53 33 -79 89 -25 54 -69 112 -121 162 -35 33 -38 40 -38 92 0 58 36 172 79 252 25 47 29 125 6 125 -19 0 -30 -22 -50 -100 -9 -35 -24 -78 -32 -94 l-16 -30 -19 24 -20 25 7 -58 c8 -62 0 -127 -16 -127 -19 0 -122 107 -166 172 -52 79 -68 150 -60 273 8 108 17 129 67 149 58 23 97 64 105 109 9 47 -5 49 -63 6 l-42 -30 15 35 c17 41 20 102 5 111 -18 11 -45 -4 -64 -36 -11 -19 -20 -60 -23 -110 -4 -54 -10 -79 -18 -79 -20 0 -27 28 -30 108 -2 40 -6 76 -9 79 -3 4 -6 51 -6 105 0 86 -3 101 -21 119 -27 27 -42 20 -53 -24 -7 -28 -5 -51 7 -90 9 -30 17 -76 17 -103 l0 -49 -29 51 c-29 49 -92 114 -111 114 -6 0 -10 -11 -10 -25 0 -14 5 -25 10 -25 6 0 10 -6 10 -13 0 -7 23 -44 51 -82 61 -84 59 -82 52 -57 -3 14 2 24 15 31 12 6 23 23 25 38 2 16 5 2 6 -29 1 -46 -2 -58 -14 -58 -21 0 -19 -13 10 -70 22 -44 25 -61 25 -165 l0 -116 -47 27 c-65 36 -142 118 -176 187 -15 31 -37 62 -49 68 -21 11 -21 10 -15 -41 l6 -52 -29 6 c-37 7 -39 -7 -4 -31 14 -10 53 -40 86 -68 92 -76 130 -104 163 -119 39 -19 101 -84 109 -116 10 -42 50 -88 217 -245 50 -47 94 -102 134 -167 33 -54 65 -98 71 -98 17 0 45 -79 51 -145 4 -47 0 -76 -20 -135 -14 -41 -39 -121 -56 -177 -18 -57 -35 -103 -40 -103 -4 0 -26 13 -49 30 -31 22 -50 49 -82 117 -99 209 -116 241 -185 337 -123 172 -123 173 -128 311 -5 140 -29 245 -57 245 -12 0 -20 -11 -24 -31 -9 -46 -7 -108 3 -127 14 -26 25 -162 14 -162 -20 0 -160 99 -192 135 -19 22 -42 58 -52 80 -10 23 -27 52 -37 66 -10 13 -26 38 -34 54 -9 17 -23 45 -33 64 -15 29 -16 40 -6 80 31 116 34 139 27 205 -7 57 -11 69 -28 74 -14 3 -32 30 -54 79 -21 46 -39 73 -47 70 -13 -5 -14 -15 -3 -65 l8 -33 -49 25 c-61 31 -93 40 -93 27 0 -13 43 -41 122 -79 47 -22 72 -41 83 -61 19 -38 19 -51 0 -51 -12 0 -15 -15 -16 -72 -1 -79 -12 -134 -22 -108 -3 8 -10 48 -16 89 -14 89 -25 111 -54 111 -38 0 -50 -15 -45 -54 4 -40 2 -42 -26 -21 -29 22 -36 19 -36 -20 0 -39 39 -85 125 -145 38 -27 62 -56 99 -120 45 -79 82 -177 70 -189 -2 -3 -42 3 -87 13 -45 10 -99 21 -119 26 -47 9 -103 51 -125 93 -24 44 -83 203 -94 252 -5 25 -4 59 3 91 14 68 3 140 -23 155 -12 6 -23 8 -27 5 -14 -15 -13 -115 2 -159 39 -116 0 -116 -70 1 -22 36 -31 42 -59 42 -20 0 -35 6 -39 15 -6 16 -56 21 -56 6 0 -5 23 -25 51 -44 53 -36 158 -156 188 -216 10 -20 26 -60 36 -88 11 -29 25 -53 32 -53 8 0 13 -12 13 -30 0 -26 -4 -30 -27 -31 l-28 -1 25 -7 c26 -8 177 -87 196 -102 5 -4 50 -18 100 -29 122 -29 277 -78 300 -95 10 -8 26 -15 34 -15 35 0 160 -166 160 -212 0 -22 -32 -24 -50 -4 -11 14 -100 46 -165 61 -16 3 -68 25 -115 48 -102 49 -163 56 -168 19 -9 -62 58 -104 178 -112 63 -5 103 -14 155 -37 39 -16 91 -38 117 -47 26 -9 74 -35 106 -56 52 -33 65 -48 96 -112 20 -40 39 -95 43 -122 6 -47 6 -48 -18 -41 -33 10 -69 33 -69 45 0 6 -10 10 -23 10 -13 0 -27 4 -32 9 -6 5 -27 14 -47 20 -20 7 -53 23 -73 37 -43 29 -45 29 -45 7 0 -26 80 -96 145 -127 119 -56 274 -185 311 -259 55 -107 104 -410 104 -640 0 -162 -22 -325 -45 -333 -25 -10 -72 25 -168 123 -129 131 -140 148 -182 274 -20 60 -50 142 -66 181 -16 39 -45 131 -65 202 -24 93 -55 173 -104 274 -77 158 -78 166 -32 256 31 64 27 129 -12 181 -31 40 -39 42 -65 18 -51 -49 -55 -120 -11 -208 37 -74 37 -85 3 -85 -36 0 -94 65 -137 154 -18 39 -37 80 -40 92 -3 11 -14 29 -24 40 -10 10 -28 35 -42 54 -13 19 -40 55 -61 80 -20 25 -41 63 -47 85 -6 22 -16 62 -23 89 -20 81 -95 147 -113 100 -18 -47 -6 -92 39 -147 25 -31 45 -61 45 -67 0 -15 -42 -3 -116 31 -94 44 -156 124 -184 235 -9 36 -13 41 -38 40 -39 -2 -144 113 -186 205 -31 66 -33 68 -53 54 -11 -8 -24 -11 -27 -7 -4 4 11 -24 33 -62 39 -67 43 -86 18 -86 -8 0 -8 3 1 9 11 6 9 9 -7 14 -11 3 -25 -1 -31 -7 -7 -10 0 -16 29 -24 39 -12 203 -147 215 -178 13 -34 4 -35 -48 -6 -64 37 -126 51 -126 30 0 -26 55 -67 125 -92 46 -16 80 -36 100 -58 l29 -33 -54 -3 c-79 -5 -203 14 -249 38 -47 24 -70 54 -105 140 -43 105 -115 163 -103 83 3 -21 9 -47 13 -57 4 -11 -15 4 -42 32 -62 64 -84 67 -84 14 0 -41 24 -76 61 -87 16 -6 18 -9 8 -15 -23 -15 15 -45 117 -91 52 -24 93 -48 91 -54 -10 -28 -150 -28 -190 0 -21 15 -47 5 -47 -17 0 -5 -10 -19 -22 -29 -23 -20 -23 -20 112 -14 174 8 208 8 430 0 l185 -7 84 -41 c115 -57 180 -118 225 -212 20 -41 36 -77 36 -80 0 -14 89 -126 150 -190 74 -78 120 -144 120 -175 0 -30 10 -33 -201 52 -94 38 -131 71 -218 195 -27 37 -59 77 -71 88 l-23 20 7 -40 c4 -22 12 -44 17 -49 13 -14 11 -26 -4 -26 -7 0 -29 21 -48 48 -33 45 -34 51 -39 159 -4 89 -9 116 -22 130 -17 16 -18 16 -18 0 0 -9 -7 -17 -16 -17 -14 0 -16 -9 -11 -62 3 -35 8 -74 12 -88 l7 -25 -25 27 c-41 44 -127 118 -137 118 -18 0 -10 -57 12 -85 18 -24 20 -32 10 -57 -10 -28 -9 -30 22 -43 18 -8 54 -19 79 -26 36 -9 60 -24 99 -66 80 -83 80 -83 1 -83 -80 0 -176 21 -236 51 -107 54 -234 169 -252 228 -4 14 -12 29 -17 35 -5 6 -18 25 -28 43 -24 40 -90 64 -116 42 -22 -18 -13 -84 17 -116 13 -13 42 -32 64 -42 22 -10 74 -53 115 -96 l75 -77 -75 5 c-135 8 -243 76 -336 207 -31 44 -65 87 -77 95 -37 26 -34 -9 7 -88 20 -39 34 -72 31 -75 -2 -2 -26 11 -52 31 -90 65 -143 83 -143 49 0 -32 71 -88 150 -117 41 -15 113 -47 159 -71 46 -24 99 -46 118 -50 18 -3 33 -12 33 -18 0 -12 -111 -46 -149 -46 -12 0 -29 -8 -39 -17 -10 -10 -27 -19 -37 -19 -11 -1 -45 -9 -75 -17 -58 -16 -110 -62 -110 -97 0 -39 116 -45 167 -9 11 8 34 31 52 51 28 32 50 43 144 74 145 47 222 48 404 5 70 -17 177 -38 237 -47 128 -19 202 -43 250 -79 18 -14 73 -42 122 -61 164 -66 208 -112 243 -251 36 -141 27 -167 -44 -123 -19 12 -63 23 -111 28 -117 13 -134 25 -275 193 -63 74 -193 151 -266 157 -29 2 -66 -1 -81 -7 -24 -10 -37 -9 -80 8 -66 26 -70 9 -11 -44 72 -65 119 -80 239 -78 60 1 109 -2 117 -8 6 -6 26 -35 42 -64 17 -30 46 -64 64 -77 19 -13 49 -40 67 -61 l34 -39 -79 3 c-57 3 -80 0 -83 -9 -3 -10 -7 -10 -18 -1 -8 6 -11 15 -8 20 3 5 0 9 -5 9 -16 0 -13 -16 6 -36 36 -36 78 -44 227 -44 119 0 152 -3 188 -19 56 -24 95 -64 125 -126 13 -27 35 -68 48 -90 14 -22 25 -53 25 -69 l0 -29 -107 5 c-131 6 -193 28 -290 100 -37 28 -82 56 -98 63 -75 32 -176 123 -277 247 -34 42 -122 98 -134 85 -5 -5 103 -138 184 -226 52 -57 46 -61 -49 -31 -87 28 -173 85 -325 214 -144 123 -189 151 -254 159 -25 2 -39 3 -32 0 6 -3 12 -16 12 -29 0 -17 -4 -23 -12 -19 -7 4 -1 -5 15 -19 15 -14 46 -30 70 -36 23 -6 60 -17 82 -25 l40 -13 -52 -1 c-49 -1 -53 -3 -53 -25 0 -28 28 -36 122 -36 54 0 62 -3 91 -32 l32 -33 -52 -3 c-88 -5 -75 -26 39 -62 130 -41 178 -63 206 -93 l22 -24 -20 -18 c-12 -11 -41 -20 -74 -23 -48 -4 -60 0 -116 32 -118 69 -241 96 -279 62 -13 -12 -40 -16 -104 -16 -48 0 -95 4 -105 9 -9 5 -34 16 -55 25 -20 9 -76 53 -122 97 -47 45 -88 79 -91 76 -12 -12 6 -54 41 -100 l36 -47 -74 0 c-88 0 -112 15 -78 49 26 26 21 39 -34 84 -87 73 -132 32 -50 -45 25 -23 45 -46 45 -50 0 -4 -21 2 -46 12 -45 20 -114 27 -114 12 0 -4 16 -22 35 -40 39 -38 78 -47 255 -61 164 -14 178 -17 172 -47 -2 -13 -2 -30 2 -39 5 -13 9 -13 40 2 19 9 33 20 30 25 -4 5 4 4 15 -4 21 -13 20 -15 -44 -74 -36 -33 -65 -66 -65 -72 0 -21 68 15 142 74 38 30 84 62 103 70 73 30 203 11 312 -46 32 -17 82 -33 111 -37 l53 -6 -28 -30 c-15 -16 -44 -40 -63 -52 -63 -42 -100 -82 -100 -111 0 -25 2 -26 37 -21 28 5 47 17 73 49 65 78 175 183 224 216 34 22 61 32 88 32 43 0 122 -36 152 -69 10 -11 39 -32 62 -46 43 -25 53 -46 36 -72 -11 -17 -200 -86 -232 -85 -28 1 -122 -47 -127 -65 -3 -8 14 -13 54 -15 l58 -3 -65 -44 c-36 -25 -68 -49 -71 -53 -11 -17 -115 -10 -188 12 -105 32 -112 11 -14 -39 l56 -28 -40 -6 c-52 -9 -96 0 -154 29 -31 15 -50 19 -60 13 -15 -10 -16 -10 44 -47 20 -13 37 -27 37 -31 0 -15 -144 -71 -205 -81 -33 -5 -85 -10 -116 -10 -32 0 -63 -6 -75 -14 -18 -13 -15 -15 34 -22 l53 -7 -31 -18 c-18 -12 -30 -27 -30 -40 0 -21 4 -21 61 -16 50 4 75 14 145 57 46 28 112 63 146 77 62 24 191 62 215 63 22 0 -47 -103 -107 -161 -42 -41 -60 -66 -65 -92 -10 -49 0 -60 47 -54 65 9 99 53 124 160 20 83 49 133 94 163 22 15 40 30 40 34 0 4 8 10 18 13 9 3 31 15 49 27 31 21 31 21 26 0 -3 -11 -21 -37 -40 -58 -43 -45 -72 -106 -73 -150 0 -39 18 -49 56 -30 38 18 63 64 75 137 13 82 40 142 89 194 22 24 40 49 40 54 0 6 24 21 53 34 49 22 63 23 237 20 193 -2 278 -14 348 -50 21 -11 44 -27 52 -36 7 -9 32 -27 55 -41 49 -28 138 -147 184 -243 16 -35 42 -114 57 -175 35 -147 31 -268 -14 -436 -17 -63 -37 -166 -45 -227 -12 -94 -21 -127 -54 -195 -22 -46 -52 -94 -67 -108 -15 -14 -46 -44 -68 -67 -23 -24 -47 -43 -53 -43 -7 0 -25 -12 -41 -26 -129 -121 -526 -267 -721 -268 -104 0 -109 -15 -19 -57 75 -35 67 -35 221 -10 125 21 235 27 235 13 0 -16 -66 -72 -85 -72 -24 0 -85 -36 -85 -49 0 -14 12 -19 58 -27 35 -5 42 -4 42 10 0 9 5 17 10 17 28 4 74 20 80 29 9 14 226 119 288 139 63 21 215 43 239 34 32 -12 12 -50 -52 -102 -36 -28 -73 -55 -83 -58 -17 -7 -66 -39 -92 -60 -8 -7 -38 -32 -67 -57 l-52 -45 42 -6 c36 -6 54 -1 122 33 44 22 120 56 169 76 112 45 222 107 289 164 46 40 84 62 107 62 18 0 130 -83 130 -96 0 -8 4 -14 10 -14 5 0 39 -26 75 -59 36 -32 96 -76 132 -97 36 -21 68 -46 71 -56 5 -19 21 -22 59 -12 18 5 20 9 10 19 -7 7 -69 71 -139 143 -147 149 -161 179 -80 168 136 -19 195 -39 378 -128 78 -37 147 -68 152 -68 6 0 15 -7 20 -16 8 -14 14 -15 46 -4 l38 12 -104 57 c-125 69 -148 84 -148 93 0 16 94 7 223 -22 74 -17 146 -30 160 -30 14 0 29 -4 32 -10 7 -11 54 6 115 43 l40 24 -38 1 c-22 1 -68 11 -103 21 -35 11 -107 30 -159 41 -131 31 -295 99 -406 171 -235 153 -355 366 -357 634 -1 211 65 343 285 568 117 119 206 167 368 198 153 29 267 59 328 86 80 35 166 44 264 27 148 -26 167 -38 251 -169 71 -110 136 -165 196 -165 26 0 31 4 31 23 -1 32 -28 62 -87 91 -39 20 -66 45 -118 112 -95 123 -95 135 -5 92 25 -12 77 -31 116 -43 56 -17 76 -19 97 -10 27 11 26 11 -25 29 -113 39 -138 49 -138 57 0 14 91 55 153 68 33 7 75 10 95 7 27 -4 31 -3 17 4 -19 8 -19 9 3 9 12 1 22 7 22 15 0 10 7 12 22 8 12 -3 17 -7 10 -10 -6 -2 -12 -10 -12 -18 0 -8 -6 -14 -12 -15 -27 -2 39 -17 80 -18 29 -1 42 3 42 13 0 20 -19 32 -67 45 -49 13 -53 22 -20 44 49 32 128 39 235 21 56 -9 112 -14 126 -10 26 6 96 69 96 86 0 6 -32 10 -77 10 -84 0 -126 -7 -118 -20 9 -14 -17 -24 -67 -24 -34 -1 -48 3 -48 13 0 8 -7 11 -20 8 -17 -4 -18 -2 -9 14 5 11 14 17 20 14 5 -4 9 0 9 8 0 8 16 35 35 60 35 45 35 46 14 57 -18 10 -23 8 -37 -12 -67 -95 -162 -167 -297 -225 -55 -23 -99 -47 -98 -53 2 -5 -6 -10 -18 -10 -27 0 -23 8 31 71 100 117 116 131 161 155 80 40 80 70 1 41 l-47 -18 36 38 c47 49 59 73 59 120 0 67 -24 80 -82 46 -49 -29 -76 -85 -89 -183 -10 -81 -9 -80 -89 -174 -20 -22 -43 -53 -53 -68 -28 -45 -89 -61 -217 -56 -70 2 -114 8 -118 15 -4 6 -28 13 -54 15 l-46 3 53 71 c51 68 100 104 140 104 50 0 125 73 125 122 0 30 0 31 -45 26 -28 -4 -59 -16 -82 -34 -30 -23 -35 -24 -28 -8 22 51 37 105 31 111 -13 13 -47 -34 -105 -146 -72 -138 -171 -248 -261 -292 -62 -30 -164 -44 -242 -34 -48 7 -50 8 -45 34 14 70 51 144 95 190 42 43 56 51 127 69 44 12 98 24 120 27 99 15 155 57 155 117 l0 31 -51 -5 c-40 -4 -58 -12 -87 -40 -56 -52 -66 -58 -131 -78 l-60 -18 10 27 c6 14 36 62 68 106 70 96 91 136 91 170 0 41 -18 29 -50 -35 -30 -59 -31 -60 -74 -60 -56 0 -71 -18 -101 -115 -23 -75 -43 -114 -72 -145 -8 -8 -41 -61 -73 -117 -35 -59 -75 -113 -95 -128 -37 -29 -177 -85 -210 -85 -35 0 -222 -134 -282 -202 -31 -35 -64 -64 -72 -66 -22 -4 -68 116 -88 223 -20 113 -5 256 37 340 37 76 124 182 195 238 140 110 221 137 416 137 136 0 171 6 186 28 9 15 2 17 -76 18 -47 0 -127 4 -178 9 -167 15 -274 -28 -423 -170 -72 -68 -114 -95 -128 -81 -12 12 17 138 44 194 64 132 229 243 439 298 182 46 319 21 425 -80 68 -65 144 -115 202 -135 119 -41 155 -32 72 17 -88 52 -224 144 -224 152 0 14 51 20 210 22 115 2 160 0 175 -10 19 -12 18 -13 -8 -9 -36 6 -45 -9 -11 -17 56 -15 117 -51 183 -110 66 -59 119 -86 169 -86 54 0 31 59 -35 90 -167 77 -176 82 -158 93 25 13 138 -8 201 -37 27 -13 67 -43 89 -66 50 -53 84 -70 134 -70 37 0 71 19 71 40 0 24 -62 57 -129 70 -40 7 -74 17 -77 22 -3 4 24 8 60 8 36 0 68 -4 71 -10 3 -5 26 -10 51 -10 50 0 57 15 23 46 -24 21 -113 25 -226 10 -50 -7 -65 -6 -77 7 -19 18 -100 37 -160 37 -74 0 -136 12 -136 26 0 17 11 23 53 28 32 4 83 29 97 47 8 10 71 40 99 47 28 7 159 8 309 1 50 -2 92 -1 92 4 0 4 14 7 30 7 23 0 30 -4 30 -20 0 -15 -7 -20 -25 -20 -42 0 -28 -17 30 -39 75 -28 103 -27 117 4 8 18 19 25 38 25 34 0 47 35 23 62 -24 27 -70 31 -190 18 -101 -11 -112 -10 -173 10 -36 12 -104 24 -152 27 -49 3 -88 9 -88 13 0 8 35 26 66 35 12 3 37 21 55 40 19 20 67 58 106 86 57 39 86 52 134 60 71 11 170 58 193 91 34 49 10 51 -66 5 -52 -31 -154 -65 -165 -54 -11 12 9 25 67 47 33 12 60 26 60 30 0 5 15 17 34 28 31 18 67 84 53 98 -15 15 -69 -17 -124 -75 -35 -36 -63 -63 -63 -58 0 4 14 31 30 60 43 77 39 180 -7 151 -39 -24 -56 -62 -63 -141 -7 -87 -27 -127 -98 -200 -50 -52 -120 -103 -139 -103 -8 0 -22 -8 -31 -17 -31 -31 -26 11 12 94 33 74 61 171 53 180 -3 2 -17 1 -32 -3 -38 -10 -65 -74 -75 -185 -9 -97 -31 -147 -79 -176 -31 -20 -81 -71 -81 -83 0 -5 -24 -16 -52 -26 -29 -9 -58 -24 -64 -32 -7 -9 -33 -17 -70 -19 l-59 -4 55 48 c120 105 133 126 66 103 -19 -6 -58 -36 -88 -66 -29 -30 -72 -64 -96 -76 -41 -19 -50 -20 -163 -9 -168 16 -237 52 -196 103 21 27 121 88 143 88 60 0 183 34 234 65 30 18 74 36 97 40 85 14 180 99 131 118 -16 5 -19 13 -14 33 7 25 5 25 -26 19 -52 -11 -83 -31 -122 -76 -54 -63 -94 -86 -197 -109 -52 -12 -102 -24 -111 -26 -28 -8 -22 22 10 44 15 11 35 34 45 51 16 27 16 31 2 31 -8 0 -18 -7 -22 -16 -8 -23 -23 2 -23 40 0 23 -3 27 -12 18 -14 -14 -42 -16 -33 -2 3 6 4 10 1 10 -9 0 -37 -61 -62 -133 -29 -84 -85 -162 -137 -189 -24 -12 -67 -21 -110 -24 -40 -2 -100 -6 -134 -9 l-62 -4 36 72 c20 39 48 84 62 98 29 29 86 122 96 157 9 32 -20 29 -42 -5 -17 -27 -128 -174 -222 -297 -45 -58 -101 -96 -141 -96 -48 0 -9 184 59 284 41 59 113 107 234 156 51 20 141 67 198 102 57 36 118 72 134 80 40 21 155 46 240 53 48 5 82 14 113 32 58 34 150 44 258 28 41 -6 57 -4 75 9 17 12 46 16 111 16 88 0 116 12 57 24 -17 3 -48 6 -69 6 -21 0 -43 6 -49 14 -14 17 -8 22 40 31 30 5 36 10 32 26 -4 13 0 19 12 19 23 0 95 44 129 79 34 35 30 67 -6 55 -13 -4 -31 -7 -41 -6 -11 0 -38 -25 -68 -64 -28 -35 -53 -64 -55 -64 -2 0 7 22 21 50 14 27 25 60 25 74 0 14 5 37 11 53 7 19 7 29 0 31 -6 2 -11 17 -11 33 0 16 -4 29 -10 29 -5 0 -10 -19 -10 -42 0 -50 -37 -158 -74 -222 -28 -48 -90 -86 -141 -86 l-29 0 36 38 c20 20 43 52 52 70 16 31 16 32 -5 32 -25 0 -94 -47 -109 -75 -19 -35 -161 -104 -245 -120 -42 -8 -85 -15 -96 -15 -18 0 -18 1 -2 35 9 19 20 35 25 35 4 0 8 6 8 13 0 7 13 34 30 60 30 48 75 77 182 117 58 21 112 66 176 146 26 31 57 57 84 69 124 52 167 75 177 93 17 33 -14 35 -71 6 -29 -14 -69 -32 -89 -39 l-38 -14 20 51 c11 28 24 59 29 68 10 19 -20 60 -45 60 -18 0 -21 46 -4 52 6 2 14 26 16 53 4 43 2 52 -16 63 -20 11 -21 10 -21 -25 -1 -209 -5 -248 -32 -305 -34 -73 -116 -188 -133 -188 -8 0 -20 -6 -27 -13 -7 -7 -29 -18 -48 -24 -19 -6 -52 -18 -72 -27 -34 -15 -38 -15 -38 -1 0 35 32 73 89 109 60 37 77 51 45 39 -14 -5 -14 -3 -3 14 7 13 9 28 4 39 -5 11 -7 24 -6 29 1 6 -19 -11 -44 -37 -25 -26 -45 -44 -45 -40 0 4 18 34 40 67 30 45 40 69 40 100 0 53 -11 67 -46 63 -22 -2 -34 -13 -53 -47 -14 -25 -26 -40 -29 -33 -2 7 -10 12 -17 12 -10 0 -14 -33 -17 -142 l-4 -143 -63 -127 c-39 -81 -74 -137 -94 -154 -51 -43 -167 -87 -167 -63 0 6 26 38 58 72 32 34 66 73 75 87 18 26 23 100 8 100 -5 0 -22 -19 -38 -42 -15 -23 -52 -60 -81 -82 -31 -25 -61 -59 -74 -85 -37 -75 -125 -156 -220 -201 -46 -22 -101 -43 -121 -47 -32 -5 -37 -3 -37 13 0 36 50 229 70 269 10 23 38 95 61 160 39 116 84 211 117 248 12 13 13 20 4 29 -9 9 -21 5 -49 -18 -58 -46 -166 -272 -249 -519 -37 -110 -73 -207 -80 -216 -8 -8 -14 -21 -14 -28 0 -8 -19 -54 -41 -105 -23 -50 -61 -146 -84 -212 -49 -144 -77 -193 -152 -274 -71 -77 -89 -77 -115 2 -11 33 -27 59 -36 62 -19 6 -21 27 -23 201 -2 197 49 394 151 580 33 61 72 135 86 165 118 253 140 288 273 462 87 112 121 167 121 195 0 37 -25 27 -75 -29 -42 -48 -45 -50 -38 -23 13 50 9 145 -8 156 -19 12 -30 7 -50 -22 -23 -33 -15 -116 12 -124 28 -9 35 -49 12 -73 -10 -11 -36 -45 -58 -76 -22 -31 -44 -56 -48 -56 -12 0 -3 78 17 160 8 36 15 84 16 107 0 23 4 44 9 47 4 3 11 37 14 75 3 39 14 86 26 109 26 50 80 97 94 83 16 -16 59 -13 85 5 30 21 52 66 52 109 0 33 -2 35 -32 35 -59 0 -78 -12 -118 -69 -21 -31 -55 -74 -74 -96 l-35 -40 -1 41 c0 23 7 60 15 83 15 43 92 151 124 173 20 14 55 77 48 85 -3 2 -8 -5 -12 -16 -7 -24 -35 -17 -35 9 0 23 -13 32 -35 24 -9 -4 -12 -9 -7 -13 17 -10 2 -62 -16 -59 -11 2 -30 -24 -61 -87 -34 -68 -46 -84 -49 -67 -2 12 -8 22 -13 22 -5 0 -9 -10 -9 -22 -1 -23 -1 -23 -16 -3 -9 11 -24 37 -34 58 -11 24 -20 34 -23 25 -3 -7 -6 25 -6 72 -1 105 -21 98 -26 -10 -3 -43 -9 -76 -16 -81 -10 -6 -10 -11 0 -23 14 -16 3 -22 -15 -8 -5 4 2 -2 15 -13 51 -41 78 -76 96 -128 26 -70 25 -187 -3 -292 -13 -49 -21 -109 -20 -155 0 -104 -54 -310 -81 -310 -6 0 -11 3 -11 8 -1 44 -24 191 -41 259 l-22 85 27 108 c30 123 34 211 10 231 -20 16 -40 5 -72 -42 -21 -30 -23 -42 -18 -97 3 -36 1 -60 -4 -57 -17 11 -34 81 -34 150 -1 64 2 76 39 140 22 39 45 84 52 100 17 43 16 92 -2 98 -17 7 -17 8 -44 -73 -12 -36 -34 -87 -50 -113 -33 -56 -41 -48 -41 39 0 41 -4 54 -15 54 -11 0 -15 -18 -17 -80 -2 -45 -7 -80 -13 -80 -5 0 -10 4 -10 8 0 5 -8 16 -18 26 -58 58 -70 132 -53 314 7 69 6 92 -3 92 -6 0 -13 -6 -16 -12z m321 -503 c3 -20 4 -39 0 -42 -3 -4 -6 6 -6 20 0 17 -5 27 -15 27 -16 0 -20 12 -8 23 14 14 22 6 29 -28z m-1006 -80 c0 -8 -9 -15 -19 -15 -29 0 -35 18 -9 23 13 2 24 5 26 6 1 0 2 -6 2 -14z m327 -27 c-3 -7 -5 -2 -5 12 0 14 2 19 5 13 2 -7 2 -19 0 -25z m-462 -358 c3 -5 1 -10 -4 -10 -6 0 -11 5 -11 10 0 6 2 10 4 10 3 0 8 -4 11 -10z m-835 -40 c-6 -11 -15 -20 -19 -20 -5 0 -7 9 -4 20 3 11 12 20 20 20 11 0 11 -4 3 -20z m864 -25 c3 -9 0 -15 -9 -15 -9 0 -15 -10 -16 -27 0 -27 -1 -27 -13 7 -10 25 -10 37 -2 42 18 12 33 9 40 -7z m-892 -863 c38 2 68 0 68 -4 0 -5 -33 -8 -73 -8 -49 0 -80 -5 -95 -16 -21 -14 -22 -14 -22 5 0 14 -6 21 -20 21 -11 0 -20 2 -20 4 0 2 -3 12 -6 21 -6 13 1 13 47 -5 40 -16 70 -21 121 -18z m3218 -91 c0 -10 -7 -21 -15 -25 -11 -4 -15 1 -15 19 0 16 6 25 15 25 8 0 15 -9 15 -19z m-3479 -32 c-14 -5 -30 -14 -37 -20 -8 -7 -13 -3 -17 11 -5 18 0 20 36 19 38 0 40 -1 18 -10z m3359 -572 c0 -7 -7 -22 -15 -33 -13 -17 -14 -16 -4 14 11 33 19 41 19 19z m-3345 -198 c7 -22 -7 -39 -33 -39 -10 0 -10 4 0 20 11 17 10 22 -2 30 -12 8 -11 10 7 10 13 0 24 -8 28 -21z m445 -37 c0 -23 -35 -8 -38 16 -3 21 -2 22 17 10 12 -7 21 -19 21 -26z m-310 -647 c-28 -30 -60 -33 -60 -7 0 26 9 32 48 32 l35 0 -23 -25z M3684 5414 c-14 -21 -16 -41 -10 -124 4 -62 2 -100 -3 -100 -9 0 -17 26 -25 84 -1 11 -8 22 -14 24 -9 3 -12 -27 -12 -105 0 -69 -6 -130 -16 -164 -24 -86 -24 -85 -33 -70 -6 9 -10 3 -14 -17 -4 -20 -23 -43 -59 -72 -29 -23 -54 -46 -54 -51 -1 -5 -3 -39 -4 -76 -1 -46 -4 -60 -9 -43 -6 21 -9 15 -20 -35 -16 -74 -29 -99 -97 -197 -35 -49 -54 -86 -54 -105 0 -31 59 -200 60 -171 0 9 6 21 14 25 13 7 13 16 0 68 -17 72 -12 78 75 93 106 19 127 33 145 95 20 70 65 111 186 172 83 42 89 47 75 62 -9 8 -14 23 -11 32 5 14 5 14 -6 1 -7 -8 -41 -25 -75 -37 -54 -19 -61 -19 -56 -5 10 26 43 72 91 126 46 53 77 104 68 114 -6 6 -95 -81 -143 -141 l-30 -38 -7 80 c-4 45 -5 89 -1 98 3 10 31 34 63 53 61 37 147 112 164 144 21 38 -53 8 -126 -52 -98 -80 -100 -81 -92 -46 12 47 54 133 81 166 14 16 25 42 25 56 l-1 27 -25 -30 -26 -30 6 53 c3 28 9 74 12 100 5 40 3 50 -10 55 -10 4 -22 -2 -32 -19z m-79 -654 c0 -125 0 -126 -33 -176 -22 -36 -56 -67 -109 -103 -42 -28 -82 -51 -90 -51 -20 0 -16 22 11 59 13 18 30 46 36 62 7 16 16 29 20 29 5 0 13 33 20 73 16 102 29 149 40 142 6 -4 10 -2 10 3 0 5 13 25 30 43 16 19 30 38 30 42 0 5 8 7 18 5 15 -3 17 -17 17 -128z M2287 5348 c-10 -10 -22 -16 -27 -13 -5 3 -8 -3 -8 -12 1 -10 -2 -37 -6 -59 -6 -32 -4 -43 7 -47 23 -9 67 61 67 105 0 44 -9 51 -33 26z M1853 5256 c4 -22 11 -42 17 -46 7 -4 14 -26 17 -49 3 -22 10 -41 15 -41 5 0 7 12 4 28 -3 15 -8 46 -11 69 -4 23 -16 49 -27 60 -21 18 -21 18 -15 -21z M1780 5267 c0 -47 15 -79 42 -93 l30 -16 -7 34 c-4 18 -12 44 -19 58 -12 28 -46 40 -46 17z M1960 5120 c0 -21 30 -70 49 -80 27 -14 31 -13 31 10 0 11 5 20 10 20 6 0 8 -11 4 -25 -6 -23 -4 -25 30 -25 20 0 36 4 36 8 0 18 -68 72 -109 87 -52 18 -51 18 -51 5z M4127 5076 c-4 -10 -7 -45 -7 -79 0 -42 -6 -70 -18 -88 -56 -85 -73 -107 -106 -138 -20 -19 -36 -39 -36 -43 0 -18 34 -6 62 23 29 28 34 30 84 24 41 -6 59 -3 83 11 37 22 44 37 28 59 -16 21 -72 22 -95 2 -21 -19 -32 -22 -32 -7 0 5 38 35 84 66 77 51 106 84 106 119 0 26 -43 16 -77 -17 l-33 -32 0 47 c0 34 -4 47 -14 47 -8 0 -16 5 -18 12 -3 7 -7 5 -11 -6z M1049 5043 c-8 -10 -9 -14 -2 -10 7 5 28 -18 57 -63 48 -74 62 -86 52 -45 -4 15 -2 25 4 25 15 0 -17 72 -41 93 -27 22 -53 22 -70 0z M3400 4964 c-14 -37 -12 -60 6 -75 14 -11 18 -10 30 6 19 26 18 81 -2 89 -23 9 -24 8 -34 -20z M3910 4933 c-29 -20 -40 -33 -40 -50 0 -33 63 6 75 45 8 26 -2 28 -35 5z M3401 4844 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z M4532 4829 c-8 -12 -9 -18 -3 -14 7 4 11 -8 12 -32 1 -21 4 -51 8 -68 6 -26 8 -22 13 29 5 39 3 67 -5 83 l-12 23 -13 -21z M1017 4820 c-8 -30 16 -52 65 -60 41 -6 45 -5 40 12 -5 20 -68 68 -88 68 -6 0 -14 -9 -17 -20z M2529 4778 c-11 -21 -7 -134 7 -185 8 -30 24 -19 24 17 0 16 7 35 15 44 18 17 20 70 4 115 -13 36 -33 40 -50 9z M830 4767 c0 -24 30 -116 40 -122 11 -7 1 92 -12 118 -10 20 -28 23 -28 4z M4660 4751 c0 -5 -9 -12 -19 -16 -23 -7 -101 -81 -101 -95 0 -26 50 -6 98 38 51 47 67 82 37 82 -8 0 -15 -4 -15 -9z M764 4719 c-7 -13 82 -106 92 -96 11 11 -9 43 -46 75 -27 23 -41 29 -46 21z M1887 4634 c-18 -18 -6 -91 21 -131 79 -118 125 -171 138 -159 10 9 8 18 -9 46 -12 19 -25 37 -29 38 -4 2 -8 25 -8 50 0 60 -15 115 -38 135 -20 19 -65 31 -75 21z M1030 4579 c0 -35 54 -169 68 -169 6 0 12 -8 12 -17 1 -17 2 -17 15 0 11 16 11 26 -5 71 -25 75 -47 114 -70 126 -17 9 -20 8 -20 -11z M697 4553 c19 -54 69 -92 112 -85 36 5 46 34 20 58 -11 9 -22 14 -25 11 -4 -4 -18 3 -32 13 -32 26 -84 28 -75 3z M1150 4486 c0 -36 52 -76 101 -76 47 0 57 29 12 32 -16 1 6 4 47 8 l75 6 -75 2 c-41 1 -85 8 -96 15 -12 6 -31 18 -43 25 -19 12 -21 11 -21 -12z M3909 4427 c-16 -27 -19 -51 -19 -149 0 -111 1 -118 20 -118 15 0 24 14 40 68 39 124 39 215 -1 225 -15 4 -25 -2 -40 -26z M4723 4375 c-30 -13 -33 -18 -33 -60 l0 -45 24 15 c27 18 49 48 60 83 9 26 -4 28 -51 7z M5002 4348 c-5 -7 -23 -40 -40 -73 -32 -65 -106 -146 -156 -172 -17 -9 -51 -21 -75 -28 -46 -11 -63 -28 -38 -38 7 -3 47 2 87 10 58 12 85 13 128 4 96 -19 162 -13 162 15 0 11 -19 14 -82 15 -46 0 -91 4 -101 8 -17 6 -17 8 2 25 11 10 44 25 73 32 34 8 43 13 27 13 -31 1 -44 24 -23 41 8 7 14 21 14 31 0 11 10 36 23 57 33 52 39 72 23 72 -7 0 -18 -6 -24 -12z M3632 4290 c-52 -37 -68 -69 -74 -145 -3 -33 -3 -54 0 -47 3 10 7 9 16 -4 12 -15 18 -14 79 15 69 33 101 66 95 98 -4 22 -37 30 -49 11 -6 -8 -7 10 -3 45 8 68 -2 72 -64 27z M5016 4271 c-11 -12 -16 -24 -12 -28 9 -9 39 22 34 37 -2 7 -10 4 -22 -9z M470 4264 c0 -9 8 -28 18 -42 10 -15 22 -33 27 -40 8 -15 -67 31 -102 62 -13 11 -23 14 -23 8 0 -7 -7 -12 -15 -12 -19 0 -19 -15 2 -50 20 -35 48 -48 118 -56 37 -5 55 -11 55 -20 0 -8 11 -14 25 -14 14 0 25 4 25 10 0 5 -22 43 -50 84 -49 73 -80 100 -80 70z M2382 4102 c-5 -9 -12 -42 -14 -72 -9 -96 18 -125 39 -43 17 66 17 120 -2 127 -8 3 -19 -2 -23 -12z M4235 3850 c36 -39 118 -80 162 -80 30 0 93 41 93 61 0 5 -14 15 -30 24 -25 13 -44 14 -107 6 -43 -5 -80 -6 -83 -1 -3 5 -19 12 -35 16 l-30 7 30 -33z M133 3667 c-19 -41 -15 -59 18 -86 30 -24 135 -55 151 -45 11 7 10 42 -2 49 -5 3 -10 11 -10 17 0 6 7 5 17 -3 12 -10 15 -10 9 -1 -13 22 -84 52 -125 52 -33 0 -40 4 -43 22 -3 21 -4 21 -15 -5z M5265 3631 c-16 -10 -43 -33 -60 -51 l-30 -32 83 4 c77 3 86 6 107 30 35 41 24 68 -29 68 -23 0 -54 -8 -71 -19z M400 3512 c0 -5 -53 -12 -117 -16 -64 -4 -120 -9 -125 -12 -16 -10 -8 -53 13 -65 51 -27 183 0 213 43 13 17 19 18 68 9 29 -5 66 -13 81 -16 22 -6 26 -4 21 9 -5 12 0 16 17 17 13 1 -3 7 -36 14 -106 22 -135 26 -135 17z M5090 3480 c0 -5 9 -10 20 -10 11 0 47 -13 80 -30 57 -29 121 -39 147 -22 22 14 19 45 -7 59 -30 15 -240 18 -240 3z M926 3272 c-12 -11 -6 -94 9 -122 16 -31 39 -47 86 -60 24 -7 29 -5 39 21 19 44 5 94 -34 124 -35 27 -90 47 -100 37z M500 3049 c0 -23 9 -62 20 -85 17 -33 30 -46 70 -62 34 -14 56 -32 70 -54 16 -28 109 -108 125 -108 3 0 5 7 5 15 0 12 7 14 28 9 15 -3 -8 11 -50 32 -42 20 -80 44 -83 53 -4 9 -9 46 -12 84 -5 61 -9 70 -41 98 -34 30 -59 43 -107 55 -24 6 -25 4 -25 -37z M5203 2779 c-18 -11 -35 -29 -38 -40 -7 -22 -20 -25 -32 -6 -8 13 -20 -26 -22 -74 -1 -30 25 -36 35 -7 4 15 9 17 20 7 8 -6 14 -18 14 -26 0 -11 7 -9 27 7 43 33 63 71 63 118 0 49 -14 53 -67 21z M5307 2622 c-34 -32 -86 -72 -115 -88 -51 -29 -61 -46 -29 -52 25 -5 198 81 229 114 15 16 30 41 33 57 7 25 5 27 -24 27 -25 0 -45 -13 -94 -58z M447 2652 c-10 -10 -15 -21 -12 -24 7 -7 75 24 75 34 0 15 -47 8 -63 -10z M263 2600 c-12 -5 -26 -18 -32 -28 -8 -15 -6 -24 13 -41 33 -31 84 -27 160 13 68 36 68 47 1 51 -16 1 -50 5 -75 8 -25 4 -55 3 -67 -3z M996 2540 c-37 -11 -102 -74 -115 -112 l-10 -28 58 0 c48 0 65 5 98 29 49 35 87 86 79 106 -6 17 -62 19 -110 5z M673 2324 c-43 -18 -42 -43 1 -88 33 -35 35 -36 114 -36 70 0 80 2 78 18 0 10 6 16 16 16 13 -1 9 8 -18 40 -19 22 -45 46 -57 53 -29 16 -94 15 -134 -3z M4790 2120 c-9 -17 -5 -20 43 -29 72 -15 166 -19 169 -9 2 5 11 6 21 3 20 -8 23 -35 5 -35 -7 -1 -2 -7 12 -15 29 -17 113 -20 141 -5 24 13 25 36 2 48 -10 5 -58 12 -108 15 -49 3 -117 12 -150 20 -110 28 -124 28 -135 7z M4881 2021 c6 -17 30 -50 53 -75 33 -36 49 -46 74 -46 25 0 32 4 32 19 0 25 -60 77 -99 86 -17 4 -36 15 -41 26 -17 30 -30 23 -19 -10z\";\n","import { TREE_MARK_PATH } from \"./treeMarkPath\";\n\nexport function TreeMarkIcon({ className }: { className?: string }) {\n return (\n <svg viewBox=\"0 0 551 567\" fill=\"currentColor\" className={className} aria-hidden>\n <path transform=\"translate(0 567) scale(0.1 -0.1)\" d={TREE_MARK_PATH} />\n </svg>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { PanelSection, Skeleton } from \"@behindthemusictree/ui\";\nimport { z } from \"zod\";\n\nimport type { GenreMusicSelection } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaOverview } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useFetchGenreOverview } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaPlaylistMinimum, type GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { ClampedText } from \"./ClampedText\";\nimport CommonsPhoto from \"./CommonsPhoto\";\nimport { GenrePlaylistTracks, type GenrePlaylistTracksSlots } from \"./GenrePlaylistTracks\";\nimport type { RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\nimport { SiWikidata, SiWikipedia } from \"react-icons/si\";\n\nexport type GenreDetailSlots<O extends CriteriaOverview> = {\n /** Replaces the body of the default Summary section; the title and frame stay. */\n renderSummary?: (overview: O) => ReactNode;\n /** Replaces the body of the default Essential section (e.g. \"Essential songs\"); the title and frame stay. */\n renderEssentialTracks?: (overview: O) => ReactNode;\n};\n\nexport type GenreDetailExtrasProps<O extends CriteriaOverview> = GenreDetailSlots<O> & GenrePlaylistTracksSlots & {\n genreUuid: GenreUuid;\n genrePlaylist: CriteriaPlaylistMinimum | null;\n genreName?: string;\n selection?: GenreMusicSelection;\n wikidataId?: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n criteriaOverviewSchema?: z.ZodType<O, unknown>;\n renderGenreDetailExtras?: (overview: O) => ReactNode;\n renderArtistLink?: RenderArtistLink;\n renderSongLink?: RenderSongLink;\n /** When set, the tracks list shows only this artist's songs in the genre. */\n artist?: { uuid: string; name: string } | null;\n /** genre-tree-view's Family section, placed right after the Summary. */\n family: ReactNode;\n};\n\n// Owns the overview fetch so its pending → success transitions re-render only the info panel,\n// not the tree that renders it.\nexport function GenreDetailExtras<O extends CriteriaOverview>({\n genreUuid,\n genrePlaylist,\n genreName,\n selection,\n wikidataId,\n scope,\n getBackendBaseUrl,\n criteriaOverviewSchema,\n renderGenreDetailExtras,\n renderArtistLink,\n renderSongLink,\n renderSummary,\n renderEssentialTracks,\n family,\n ...trackSlots\n}: GenreDetailExtrasProps<O>) {\n const trackNoun = useTrackNoun();\n const { data: overview, isPending } = useFetchGenreOverview<O>(\n genreUuid,\n scope,\n getBackendBaseUrl,\n criteriaOverviewSchema,\n );\n\n if (isPending) {\n return (\n <>\n <PanelSection title=\"Summary\">\n <div aria-busy=\"true\" data-testid=\"genre-detail-extras-skeleton\">\n <Skeleton className=\"h-4 w-3/4\" />\n </div>\n </PanelSection>\n {family}\n </>\n );\n }\n if (!overview) return <>{family}</>;\n\n const { summary, summarySourceUrl, essentialSongs, image } = overview;\n const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;\n\n return (\n <>\n {image && <CommonsPhoto image={image} alt={overview.name} creditLabel=\"Image\" />}\n {(summarySourceUrl || wikidataUrl) && (\n <PanelSection title=\"Links\">\n <div className=\"flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]\">\n {summarySourceUrl && (\n <a\n href={summarySourceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]\"\n >\n <SiWikipedia aria-hidden=\"true\" className=\"h-3.5 w-3.5\" />\n Wikipedia\n </a>\n )}\n {wikidataUrl && (\n <a\n href={wikidataUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]\"\n >\n <SiWikidata aria-hidden=\"true\" className=\"h-3.5 w-3.5\" />\n Wikidata\n </a>\n )}\n </div>\n </PanelSection>\n )}\n <PanelSection title=\"Summary\">\n {renderSummary ? (\n renderSummary(overview)\n ) : (\n <ClampedText key={genreUuid} className=\"text-body text-[var(--color-text)]\">\n {summary ?? \"—\"}\n </ClampedText>\n )}\n </PanelSection>\n {family}\n {renderGenreDetailExtras?.(overview)}\n {(renderEssentialTracks || essentialSongs) && (\n <PanelSection title={`Essential ${trackNoun.plural}`}>\n {renderEssentialTracks ? (\n renderEssentialTracks(overview)\n ) : essentialSongs && essentialSongs.length > 0 ? (\n <ul className=\"text-body text-[var(--color-text)]\">\n {essentialSongs.map((track) => (\n <li key={track.uuid} className=\"py-1\">\n {track.title}\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-body text-[var(--color-text)]\">—</p>\n )}\n </PanelSection>\n )}\n <GenrePlaylistTracks\n genreUuid={genreUuid}\n genrePlaylist={genrePlaylist}\n genreName={genreName}\n selection={selection}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n {...trackSlots}\n />\n </>\n );\n}\n","\"use client\";\n\nimport { useLayoutEffect, useRef, useState } from \"react\";\n\ntype ClampedTextProps = {\n children: string;\n className?: string;\n};\n\nexport function ClampedText({ children, className = \"\" }: ClampedTextProps) {\n const ref = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (!element || expanded) return;\n setOverflows(element.scrollHeight > element.clientHeight);\n }, [children, expanded]);\n\n return (\n <>\n <p ref={ref} className={`${className} ${expanded ? \"\" : \"line-clamp-3\"}`}>\n {children}\n </p>\n {(overflows || expanded) && (\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((value) => !value)}\n className=\"mt-1 text-caption text-[var(--color-text-muted)] underline hover:text-[var(--color-text)]\"\n >\n {expanded ? \"Show less\" : \"Show more\"}\n </button>\n )}\n </>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { CommonsImage } from \"@behindthemusictree/app-kit/genre-tree\";\n\nfunction ExternalLink({ href, children }: { href: string; children: ReactNode }) {\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"underline-offset-2 hover:underline\">\n {children}\n </a>\n );\n}\n\nexport default function CommonsPhoto({\n image,\n alt,\n creditLabel = \"Photo\",\n}: {\n image: CommonsImage;\n alt: string;\n creditLabel?: string;\n}) {\n return (\n <figure className=\"flex flex-col gap-1.5\">\n <img src={image.url} alt={alt} className=\"h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded\" />\n <figcaption className=\"text-caption text-[var(--color-text-muted)]\">\n {creditLabel}: <ExternalLink href={image.pageUrl}>{image.author ?? \"Wikimedia Commons\"}</ExternalLink>,{\" \"}\n {image.licenseUrl ? <ExternalLink href={image.licenseUrl}>{image.license}</ExternalLink> : image.license}\n </figcaption>\n </figure>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState, type ReactNode } from \"react\";\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport { z } from \"zod\";\nimport { FaPlay, FaPause } from \"react-icons/fa\";\nimport { PanelSection, RingLoader, Skeleton } from \"@behindthemusictree/ui\";\n\nimport { useSession } from \"@behindthemusictree/app-kit/auth\";\nimport { usePlaybackContext, usePlaybackFetch } from \"@behindthemusictree/app-kit/transport\";\nimport { PaginatedResponseSchema } from \"@behindthemusictree/app-kit/transport\";\nimport { parseWithLog } from \"@behindthemusictree/app-kit/transport\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport { PlayStates } from \"@behindthemusictree/app-kit/player\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport InternalErrorPopup from \"../popup/InternalErrorPopup\";\nimport { AppError, ErrorCode } from \"@behindthemusictree/app-kit/transport\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { genreMusicQueryParams, type GenreMusicSelection } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { genrePlaylistQueryKeys } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { libraryEndpoints, libraryQueryKeys } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaPlaylistMinimum, type GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { isSong, songUnplayableReason, SongDetailedSchema } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { GenrePlaylistTracksPage, TracksFailureAlreadyReportedError, useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { MusicBrainzRecordingLink } from \"./MusicBrainzRecordingLink\";\nimport { ArtistNames, RenderArtistLink, type RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { capitalize, useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\n\nconst CATALOGUE_PAGE_SIZE = 100;\n// withTotal=false: the backend skips COUNT(*) and pages by keyset cursor, so huge genre subtrees\n// stay O(page) at any depth; page numbers and totals are then null.\nconst SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({\n overallTotal: z.number().nullable(),\n page: z.number().nullable(),\n totalPages: z.number().nullable(),\n});\n\n// Container query on the list (arbitrary variant: Tailwind 3 core has no `@container`): once the\n// list is wide (expanded info panel), title, artist and album become columns instead of one line.\n// Class names stay literal so Tailwind's scanner sees them.\nconst TEXT_CELL = \"min-w-0 flex-1 truncate [@container(min-width:40rem)]:flex [@container(min-width:40rem)]:gap-2\";\nconst TITLE_CELL = \"[@container(min-width:40rem)]:flex-[2] [@container(min-width:40rem)]:truncate\";\nconst COLUMN_CELL = \"[@container(min-width:40rem)]:flex-1 [@container(min-width:40rem)]:truncate\";\nconst ALBUM_CELL = `hidden [@container(min-width:40rem)]:block ${COLUMN_CELL}`;\nconst SEPARATOR = \"[@container(min-width:40rem)]:hidden\";\n\nconst nextCursor = (next: string): string => {\n const cursor = new URL(next).searchParams.get(\"cursor\");\n if (!cursor) throw new Error(`Songs next link has no cursor: ${next}`);\n return cursor;\n};\n\n// Songs are not narrowed to SongDetailed here: \"me\" scope lists uploaded tracks too.\nexport type GenrePlaylistTracksSlots = {\n /** Rendered first in each row, e.g. a selection checkbox. `index` is the row's position in the loaded list. */\n renderSongLeading?: (song: TrackBase, index: number) => ReactNode;\n /** Rendered last in each row. The song's own genre is `song.genre`. */\n renderSongActions?: (song: TrackBase) => ReactNode;\n /** Rendered between the title and the list, e.g. a \"+ Link\" button or a selection bar. */\n renderTracksToolbar?: () => ReactNode;\n};\n\nexport type GenrePlaylistTracksProps = GenrePlaylistTracksSlots & {\n genreUuid: GenreUuid;\n genrePlaylist: CriteriaPlaylistMinimum | null;\n genreName?: string;\n selection?: GenreMusicSelection;\n scope: Scope;\n getBackendBaseUrl: () => string;\n /** When set, artist names render through it (e.g. a router `Link`). */\n renderArtistLink?: RenderArtistLink;\n /** When set, song titles render through it (e.g. open the song panel) instead of linking to MusicBrainz. */\n renderSongLink?: RenderSongLink;\n /** When set, lists and plays only this artist's songs in the genre. */\n artist?: { uuid: string; name: string } | null;\n};\n\n/**\n * \"reference\" lists the genre's whole songs catalogue (genre subtree), playable or not, while\n * row playback uses the playable catalogue. The genre Play action uses playlist members. Other scopes have no catalogue endpoint; their\n * playlist is the catalogue (e.g. hear's uploaded tracks are always playable).\n */\nexport function GenrePlaylistTracks({\n genreUuid,\n genrePlaylist,\n genreName: selectedGenreName,\n selection,\n scope,\n getBackendBaseUrl,\n renderArtistLink,\n renderSongLink,\n renderSongLeading,\n renderSongActions,\n renderTracksToolbar,\n artist = null,\n}: GenrePlaylistTracksProps) {\n const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = useTrackList();\n const { session, sessionRestored } = useSession();\n const { playerTrackObject, playState, handlePlayPauseAction } = usePlayer();\n const { showPopup } = usePopup();\n const trackNoun = useTrackNoun();\n const uuid = genrePlaylist?.uuid;\n const genreName = selectedGenreName ?? genrePlaylist?.name ?? \"Genre\";\n\n const { fetchBound } = usePlaybackFetch(getBackendBaseUrl);\n const playback = usePlaybackContext();\n\n const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteQuery({\n queryKey: [...(\n scope === \"me\"\n ? (uuid ? genrePlaylistQueryKeys.me.tracks(uuid) : [\"missing-personal-genre-playlist\", genreUuid])\n : artist\n ? [...libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), \"artist\", artist.uuid]\n : libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection)\n ), ...(playback.key ? [playback.key] : [])],\n queryFn: async ({ pageParam }): Promise<Omit<GenrePlaylistTracksPage<TrackBase>, \"total\" | \"nextPage\"> & { total: number | null; nextPage: number | string | null }> => {\n if (scope === \"me\") {\n if (!uuid) throw new Error(\"Personal genre has no playlist\");\n return fetchGenrePlaylistTracksPage(uuid, scope, Number(pageParam));\n }\n const response = await fetchBound(\n libraryEndpoints.reference.songs.list(),\n true,\n false,\n {},\n { genre: genreUuid, ...genreMusicQueryParams(selection), ...(artist && { artist: artist.uuid }), pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...(pageParam && { cursor: pageParam }) },\n );\n const parsed = parseWithLog(SongPageSchema, response, \"GenrePlaylistTracks\");\n return { tracks: parsed.results, total: parsed.overallTotal, nextPage: parsed.next ? nextCursor(parsed.next) : null };\n },\n initialPageParam: scope === \"me\" ? 1 : \"\",\n getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,\n enabled: playback.ready && (scope !== \"me\" || (uuid !== undefined && sessionRestored && !!session?.accessToken)),\n retry: (failureCount, error) => failureCount < 1 && error instanceof DOMException && error.name === \"AbortError\",\n retryDelay: 0,\n });\n\n // State, not a ref object: PanelSection unmounts its body when collapsed, so the observer must\n // re-attach when the sentinel remounts.\n const [sentinel, setSentinel] = useState<HTMLLIElement | null>(null);\n useEffect(() => {\n if (!hasNextPage || isFetchingNextPage || !sentinel) return;\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n void fetchNextPage();\n }\n });\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasNextPage, isFetchingNextPage, fetchNextPage, sentinel]);\n\n const pages = data?.pages ?? [];\n const tracks = pages.flatMap((page) => page.tracks);\n const total = pages[0]?.total ?? undefined;\n\n const play = (startSongUuid: string) => {\n const started = artist\n ? playNewTrackListFromArtist(artist, scope, {\n startSongUuid, ordering: \"title\", genreUuid, ...(selection && { selection }),\n })\n : scope === \"reference\"\n ? playNewTrackListFromGenreCatalogue({ uuid: genreUuid, name: genreName }, scope, { startSongUuid, ...(selection && { selection }) })\n : genrePlaylist ? playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid }) : Promise.reject(new Error(\"Personal genre has no playlist\"));\n started.catch((error) => {\n console.error(\"Failed to play genre playlist:\", error);\n if (error instanceof TracksFailureAlreadyReportedError) return;\n showPopup(<InternalErrorPopup errorCode={error instanceof AppError ? error.code : ErrorCode.CLIENT_UNKNOWN} />);\n });\n };\n\n return (\n <PanelSection title={`${capitalize(trackNoun.plural)}${total !== undefined ? ` (${total})` : \"\"}`}>\n <div>\n {renderTracksToolbar?.()}\n {scope === \"me\" && !genrePlaylist ? (\n <p>—</p>\n ) : isPending ? (\n <Skeleton className=\"h-4 w-3/4\" aria-busy=\"true\" />\n ) : isError && tracks.length === 0 ? (\n <p role=\"alert\">\n Couldn&apos;t load {trackNoun.plural}.{\" \"}\n <button type=\"button\" className=\"underline\" onClick={() => void refetch()}>\n Retry\n </button>\n </p>\n ) : tracks.length === 0 ? (\n <p>—</p>\n ) : (\n <ul className=\"mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]\" aria-label={`${genreName} ${trackNoun.plural}`}>\n {tracks.map((track, index) => {\n const label = track.artists?.length\n ? `${track.title} — ${track.artists.map((artist) => artist.name).join(\", \")}`\n : track.title;\n const isCurrent = playerTrackObject?.track.id === track.uuid;\n const isPlaying = isCurrent && playState === PlayStates.PLAYING;\n const text = (\n <span className={TEXT_CELL}>\n <span className={TITLE_CELL}>\n {renderSongLink ? (\n renderSongLink(track)\n ) : isSong(track) ? (\n <MusicBrainzRecordingLink song={track} className=\"hover:underline focus-visible:underline\">\n {track.title}\n </MusicBrainzRecordingLink>\n ) : (\n track.title\n )}\n </span>\n {track.artists?.length ? <span className={SEPARATOR}>{\" — \"}</span> : null}\n <span className={COLUMN_CELL}>\n {track.artists?.length ? (\n <ArtistNames artists={track.artists} renderArtistLink={renderArtistLink} />\n ) : null}\n </span>\n {track.album && <span className={ALBUM_CELL}>{track.album.name}</span>}\n </span>\n );\n const leading = renderSongLeading?.(track, index);\n const actions = renderSongActions?.(track);\n const isUnplayable = isSong(track) && songUnplayableReason(track) !== null;\n if (isUnplayable) {\n return (\n <li key={track.uuid} className=\"flex min-h-8 items-center gap-1 px-1 opacity-50\">\n {leading}\n <button\n type=\"button\"\n disabled\n aria-disabled=\"true\"\n aria-label={label}\n className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed\"\n >\n <FaPlay size={10} />\n </button>\n {text}\n {actions}\n </li>\n );\n }\n return (\n <li\n key={track.uuid}\n className={`group flex min-h-8 items-center gap-1 rounded px-1 hover:bg-[var(--color-neutral-100)] ${isCurrent ? \"font-medium text-[var(--color-primary)]\" : \"\"}`}\n >\n {leading}\n <button\n type=\"button\"\n aria-label={`${isPlaying ? \"Pause\" : \"Play\"} ${label}`}\n className={`flex h-6 w-6 shrink-0 items-center justify-center rounded-full cursor-pointer group-hover:opacity-100 focus-visible:opacity-100 ${isCurrent && playState !== PlayStates.STOPPED ? \"opacity-100\" : \"opacity-0 [@media(pointer:coarse)]:opacity-100\"}`}\n onClick={() => (isCurrent ? handlePlayPauseAction() : play(track.uuid))}\n >\n {isCurrent && playState === PlayStates.LOADING ? (\n <RingLoader size={10} />\n ) : isPlaying ? (\n <FaPause size={10} />\n ) : (\n <FaPlay size={10} />\n )}\n </button>\n {text}\n {actions}\n </li>\n );\n })}\n {hasNextPage && <li ref={setSentinel} aria-hidden=\"true\" className=\"h-4\" />}\n </ul>\n )}\n </div>\n </PanelSection>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { SongDetailed, musicBrainzRecordingUrl } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport function MusicBrainzRecordingLink({\n song,\n children,\n className = \"\",\n}: {\n song: SongDetailed;\n children: ReactNode;\n className?: string;\n}) {\n const url = musicBrainzRecordingUrl(song);\n if (!url) return <>{children}</>;\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`View ${song.title} on MusicBrainz`}\n className={className}\n onClick={(event) => event.stopPropagation()}\n >\n {children}\n </a>\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\n\nimport {\n CriteriaPlaylistSimple,\n ReparentCandidate,\n type GenreUuid,\n getReparentCandidates,\n useUpdateGenre,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport BasePopup from \"../popup/BasePopup\";\nimport GenreSearch from \"./GenreSearch\";\n\nexport type ParentChange = { genre: GenreUuid; from: GenreUuid | null; to: GenreUuid };\n\ntype ChangeParentPopupProps = {\n genrePlaylist: ReparentCandidate;\n genrePlaylists: CriteriaPlaylistSimple[];\n scope: Scope;\n getBackendBaseUrl: () => string;\n onClose: () => void;\n onParentChanged?: (change: ParentChange) => void;\n};\n\nexport default function ChangeParentPopup({\n genrePlaylist,\n genrePlaylists,\n scope,\n getBackendBaseUrl,\n onClose,\n onParentChanged,\n}: ChangeParentPopupProps) {\n const { mutate, isPending, formErrors } = useUpdateGenre(scope, getBackendBaseUrl);\n const candidates = useMemo(\n () => getReparentCandidates(genrePlaylists, genrePlaylist.uuid),\n [genrePlaylists, genrePlaylist.uuid],\n );\n\n const handleSelect = (newParent: ReparentCandidate) => {\n const genre = genrePlaylist.criteria.uuid;\n const parentPlaylistUuid = genrePlaylist.parent?.uuid;\n const from = parentPlaylistUuid\n ? (genrePlaylists.find(({ uuid }) => uuid === parentPlaylistUuid)?.criteria?.uuid ?? null)\n : null;\n mutate(\n { uuid: genre, data: { parent: newParent.criteria.uuid } },\n {\n onSuccess: () => {\n onClose();\n onParentChanged?.({ genre, from, to: newParent.criteria.uuid });\n },\n },\n );\n };\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n return (\n <BasePopup title={`Change parent of ${genrePlaylist.name}`} onClose={onClose} showCancelButton fitContent>\n <p className=\"mb-3 text-body text-[var(--color-text-muted)]\">\n Current parent: {genrePlaylist.parent?.name ?? \"none\"}\n </p>\n <div aria-busy={isPending} className={isPending ? \"pointer-events-none opacity-60\" : undefined}>\n <GenreSearch\n genrePlaylists={candidates}\n onSelect={handleSelect}\n placeholder=\"Search a new parent…\"\n />\n </div>\n {formErrors.length > 0 && (\n <p role=\"alert\" className=\"mt-3 text-body text-[var(--color-red-500)]\">\n {formErrors.map(({ message }) => message).join(\" \")}\n </p>\n )}\n </BasePopup>\n );\n}\n","\"use client\";\n\nimport { Skeleton } from \"@behindthemusictree/ui\";\nimport {\n useArtist,\n type RenderArtistLink,\n type RenderPlaceLink,\n type RenderSongLink,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport ArtistActionBand from \"./ArtistActionBand\";\nimport ArtistHeader from \"./ArtistHeader\";\nimport ArtistPhoto from \"./ArtistPhoto\";\nimport ArtistMembers from \"./ArtistMembers\";\nimport ArtistDiscography from \"./ArtistDiscography\";\nimport ArtistSongs from \"./ArtistSongs\";\nimport ShareActionButton from \"../ShareActionButton\";\nimport type { GetGenreTreeShareUrl } from \"../share\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { OverlayPanel } from \"../overlayPanel\";\n\nexport interface ArtistPanelOptions {\n uuid: string | null;\n scope?: Scope;\n getBackendBaseUrl: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n /** Renders member and song artist names. */\n renderArtistLink: RenderArtistLink;\n renderSongLink?: RenderSongLink;\n /** Renders the artist's origin as a link to its map region; plain text when omitted. */\n renderPlaceLink?: RenderPlaceLink;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n onClose: () => void;\n}\n\n/** The artist detail overlay panel for `uuid`, or undefined when no artist is set. */\nexport function useArtistPanel({\n uuid,\n scope,\n getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n expanded,\n onExpandedChange,\n onClose,\n}: ArtistPanelOptions): OverlayPanel | undefined {\n const result = useArtist(uuid, getBackendBaseUrl);\n\n const panel = { expanded, onExpandedChange, onClose };\n switch (result.status) {\n case \"idle\":\n return undefined;\n case \"loading\":\n return {\n ...panel,\n title: \"Artist\",\n content: (\n <div aria-busy=\"true\" className=\"flex flex-col gap-2.5\">\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-16 mt-2.5\" />\n <Skeleton className=\"h-16\" />\n </div>\n ),\n };\n case \"not-found\":\n return {\n ...panel,\n title: \"Artist not found\",\n content: <p className=\"text-[var(--color-text-muted)]\">This artist does not exist.</p>,\n };\n case \"error\":\n return {\n ...panel,\n title: \"Artist\",\n content: <p className=\"text-red-600\">Could not load this artist.</p>,\n };\n case \"success\": {\n const { artist } = result;\n const shareTarget = scope\n ? { kind: \"artist\" as const, uuid: artist.uuid, name: artist.name, scope }\n : undefined;\n const shareUrl = shareTarget ? getShareUrl?.(shareTarget) : undefined;\n return {\n ...panel,\n title: artist.name,\n content: (\n <>\n <ArtistActionBand\n artist={artist}\n share={shareTarget && shareUrl ? <ShareActionButton target={shareTarget} url={shareUrl} /> : undefined}\n />\n {artist.image && <ArtistPhoto image={artist.image} name={artist.name} />}\n <ArtistHeader artist={artist} renderPlaceLink={renderPlaceLink} />\n <ArtistMembers title=\"Members\" memberships={artist.members} renderArtistLink={renderArtistLink} />\n <ArtistMembers title=\"Member of\" memberships={artist.memberOf} renderArtistLink={renderArtistLink} />\n {artist.tracksCount > 0 && (\n <ArtistSongs\n artist={{ uuid: artist.uuid, name: artist.name }}\n getBackendBaseUrl={getBackendBaseUrl}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n )}\n </>\n ),\n extraContent: artist.albums.length > 0 ? <ArtistDiscography albums={artist.albums} /> : undefined,\n };\n }\n }\n}\n","\"use client\";\n\nimport { Pause, Play } from \"lucide-react\";\nimport { ActionBand, ActionButton, PanelBleed } from \"@behindthemusictree/ui\";\nimport { TrackListOriginType, useTrackList, type ArtistDetailed, type SongDetailed } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport type { ReactNode } from \"react\";\n\ntype ArtistActionBandProps = {\n artist: Pick<ArtistDetailed, \"uuid\" | \"name\" | \"playableTracksCount\">;\n /** Share button, when the host provides a share URL. */\n share?: ReactNode;\n};\n\n/** The artist panel's action band: Play over the artist's playable songs, with their count. */\nexport default function ArtistActionBand({ artist, share }: ArtistActionBandProps) {\n const { trackList, playNewTrackListFromArtist } = useTrackList<SongDetailed>();\n const { isPlaying, setIsPlaying } = usePlayer();\n const origin = trackList?.origin;\n const isCurrent = origin?.type === TrackListOriginType.ARTIST && origin.uuid === artist.uuid;\n const playing = isCurrent && isPlaying;\n const handleClick = () => {\n if (isCurrent) {\n setIsPlaying(!isPlaying);\n return;\n }\n playNewTrackListFromArtist({ uuid: artist.uuid, name: artist.name }, \"reference\", { ordering: \"title\" }).catch((error) => {\n console.error(\"Failed to load artist tracks:\", error);\n });\n };\n return (\n <PanelBleed>\n <ActionBand>\n <ActionButton\n icon={playing ? <Pause aria-hidden=\"true\" className=\"w-5 h-5\" /> : <Play aria-hidden=\"true\" className=\"w-5 h-5\" />}\n label={playing ? \"Pause\" : \"Play\"}\n caption={String(artist.playableTracksCount)}\n disabled={artist.playableTracksCount === 0}\n title={artist.playableTracksCount === 0 ? \"No playable songs\" : undefined}\n onClick={handleClick}\n />\n {share}\n </ActionBand>\n </PanelBleed>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { FieldList } from \"@behindthemusictree/ui\";\nimport type { ArtistDetailed, ArtistOrigin, RenderPlaceLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport ArtistLinks, { artistLinks } from \"./ArtistLinks\";\nimport { formatYears } from \"./formatYears\";\n\nconst countryNames = new Intl.DisplayNames([\"en\"], { type: \"region\" });\n\nfunction originLabel(artist: ArtistDetailed, origin: ArtistOrigin): string {\n if (origin.source === \"area\") return \"From\";\n if (artist.type === \"person\") return \"Born in\";\n if (artist.type === \"group\") return \"Formed in\";\n return \"From\";\n}\n\nfunction OriginValue({\n origin,\n country,\n renderPlaceLink,\n}: {\n origin: ArtistOrigin;\n country: string | undefined;\n renderPlaceLink?: RenderPlaceLink;\n}) {\n const place =\n renderPlaceLink && origin.regionId !== null ? renderPlaceLink({ ...origin, regionId: origin.regionId }) : origin.name;\n return (\n <>\n {place}\n {country && origin.kind !== \"country\" && `, ${country}`}\n </>\n );\n}\n\nexport default function ArtistHeader({\n artist,\n renderPlaceLink,\n}: {\n artist: ArtistDetailed;\n renderPlaceLink?: RenderPlaceLink;\n}) {\n const fields: { label: string; value: ReactNode }[] = [];\n if (artist.type) fields.push({ label: \"Type\", value: artist.type.charAt(0).toUpperCase() + artist.type.slice(1) });\n const country = artist.country ? countryNames.of(artist.country) : undefined;\n if (artist.origin) {\n fields.push({\n label: originLabel(artist, artist.origin),\n value: <OriginValue origin={artist.origin} country={country} renderPlaceLink={renderPlaceLink} />,\n });\n }\n if (country && !artist.origin) fields.push({ label: \"Country\", value: country });\n const years = formatYears(artist.beginYear, artist.endYear, artist.ended);\n if (years) fields.push({ label: \"Active\", value: years });\n const links = artistLinks(artist);\n if (links.length > 0) fields.push({ label: \"Links\", value: <ArtistLinks links={links} /> });\n\n if (fields.length === 0) return null;\n return <FieldList items={fields} />;\n}\n","import type { ComponentType } from \"react\";\nimport { Globe, Share2 } from \"lucide-react\";\nimport {\n SiBandcamp,\n SiDiscogs,\n SiMusicbrainz,\n SiSoundcloud,\n SiSpotify,\n SiWikidata,\n SiWikipedia,\n SiYoutube,\n} from \"react-icons/si\";\nimport { Chip } from \"@behindthemusictree/ui\";\nimport type { ArtistDetailed, ArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\n\nconst LINK_KINDS: Record<ArtistLink[\"kind\"], { label: string; Icon: ComponentType<{ className?: string }> }> = {\n official: { label: \"Official website\", Icon: Globe },\n wikipedia: { label: \"Wikipedia\", Icon: SiWikipedia },\n wikidata: { label: \"Wikidata\", Icon: SiWikidata },\n spotify: { label: \"Spotify\", Icon: SiSpotify },\n youtube: { label: \"YouTube\", Icon: SiYoutube },\n bandcamp: { label: \"Bandcamp\", Icon: SiBandcamp },\n soundcloud: { label: \"SoundCloud\", Icon: SiSoundcloud },\n discogs: { label: \"Discogs\", Icon: SiDiscogs },\n social: { label: \"Social\", Icon: Share2 },\n};\n\nfunction socialLabel(url: string): string {\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n } catch {\n return LINK_KINDS.social.label;\n }\n}\n\ninterface ArtistLinkItem {\n key: string;\n url: string;\n Icon: ComponentType<{ className?: string }>;\n label: string;\n}\n\nexport function artistLinks(artist: ArtistDetailed): ArtistLinkItem[] {\n const links = artist.links.map(({ kind, url }) => ({\n key: `${kind}-${url}`,\n url,\n Icon: LINK_KINDS[kind].Icon,\n label: kind === \"social\" ? socialLabel(url) : LINK_KINDS[kind].label,\n }));\n if (artist.musicbrainzArtistId) {\n links.push({\n key: \"musicbrainz\",\n url: `https://musicbrainz.org/artist/${artist.musicbrainzArtistId}`,\n Icon: SiMusicbrainz,\n label: \"MusicBrainz\",\n });\n }\n return links;\n}\n\nexport default function ArtistLinks({ links }: { links: ArtistLinkItem[] }) {\n return (\n <ul className=\"flex flex-wrap gap-1.5\">\n {links.map(({ key, url, Icon, label }) => (\n <li key={key}>\n <Chip href={url} icon={<Icon className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" />}>\n {label}\n </Chip>\n </li>\n ))}\n </ul>\n );\n}\n","/** \"1994–present\", \"1994–2008\", \"?–2008\", or null when nothing is known. */\nexport function formatYears(beginYear: number | null, endYear: number | null, ended: boolean): string | null {\n if (beginYear === null && endYear === null) return ended ? \"ended\" : null;\n const end = endYear ?? (ended ? \"?\" : \"present\");\n return `${beginYear ?? \"?\"}–${end}`;\n}\n","import type { ArtistImage } from \"@behindthemusictree/app-kit/genre-tree\";\nimport CommonsPhoto from \"../CommonsPhoto\";\n\nexport default function ArtistPhoto({ image, name }: { image: ArtistImage; name: string }) {\n return <CommonsPhoto image={image} alt={name} />;\n}\n","import type { ArtistMembership, RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PanelGroup, PanelSection } from \"@behindthemusictree/ui\";\nimport { formatYears } from \"./formatYears\";\n\ninterface MembershipListProps {\n title: string;\n memberships: ArtistMembership[];\n renderArtistLink: RenderArtistLink;\n}\n\nfunction MembershipList({ title, memberships, renderArtistLink }: MembershipListProps) {\n if (memberships.length === 0) return null;\n return (\n <PanelGroup title={title}>\n <ul>\n {memberships.map((membership, index) => {\n const details = [\n formatYears(membership.beginYear, membership.endYear, membership.ended),\n ...membership.roles,\n ];\n const detailsText = details.filter(Boolean).join(\" · \");\n return (\n // A member can have several periods in the same group.\n <li key={`${membership.artist.uuid}-${index}`} className=\"truncate py-0.5\" title={detailsText || undefined}>\n <span className=\"font-medium text-[var(--color-text)]\">{renderArtistLink(membership.artist)}</span>\n {detailsText && <span className=\"text-[var(--color-text-muted)]\"> — {detailsText}</span>}\n </li>\n );\n })}\n </ul>\n </PanelGroup>\n );\n}\n\nexport default function ArtistMembers({ title, memberships, renderArtistLink }: MembershipListProps) {\n if (memberships.length === 0) return null;\n const isCurrent = (membership: ArtistMembership) => !membership.ended && membership.endYear === null;\n\n return (\n <PanelSection title={title}>\n <MembershipList title=\"Current\" memberships={memberships.filter(isCurrent)} renderArtistLink={renderArtistLink} />\n <MembershipList\n title=\"Past\"\n memberships={memberships.filter((membership) => !isCurrent(membership))}\n renderArtistLink={renderArtistLink}\n />\n </PanelSection>\n );\n}\n","import type { ArtistAlbum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PanelGroup, PanelSection } from \"@behindthemusictree/ui\";\n\nconst GROUPS = [\"Albums\", \"EPs\", \"Singles\", \"Live\", \"Compilations\", \"Other\"] as const;\ntype Group = (typeof GROUPS)[number];\n\nconst PRIMARY_GROUPS: Record<string, Group> = { album: \"Albums\", ep: \"EPs\", single: \"Singles\" };\n\n// Secondary types win over the primary one: a live album belongs with live releases, not studio albums.\nexport function discographyGroup({ primaryType, secondaryTypes }: ArtistAlbum): Group {\n const secondary = secondaryTypes.map((type) => type.toLowerCase());\n if (secondary.includes(\"live\")) return \"Live\";\n if (secondary.includes(\"compilation\")) return \"Compilations\";\n return PRIMARY_GROUPS[primaryType?.toLowerCase() ?? \"\"] ?? \"Other\";\n}\n\nfunction byYear(a: ArtistAlbum, b: ArtistAlbum): number {\n if (a.year !== b.year) {\n if (a.year === null) return 1;\n if (b.year === null) return -1;\n return a.year.localeCompare(b.year);\n }\n return a.name.localeCompare(b.name);\n}\n\nexport default function ArtistDiscography({ albums }: { albums: ArtistAlbum[] }) {\n if (albums.length === 0) return null;\n const sorted = [...albums].sort(byYear);\n\n return (\n <PanelSection title=\"Discography\">\n {GROUPS.map((group) => {\n const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);\n if (groupAlbums.length === 0) return null;\n return (\n <PanelGroup key={group} title={group}>\n <ul>\n {groupAlbums.map((album) => (\n <li key={album.uuid} className=\"grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5\">\n <span className=\"tabular-nums text-[var(--color-text-muted)]\">{album.year ?? \"—\"}</span>\n <span className=\"truncate text-[var(--color-text)]\" title={album.name}>\n {album.name}\n </span>\n </li>\n ))}\n </ul>\n </PanelGroup>\n );\n })}\n </PanelSection>\n );\n}\n","\"use client\";\n\nimport { useState, type MouseEvent } from \"react\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Pagination, PanelSection, Skeleton } from \"@behindthemusictree/ui\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport {\n SongDetailedSchema,\n libraryEndpoints,\n songUnplayableReason,\n useTrackList,\n type RenderArtistLink,\n type RenderSongLink,\n type SongDetailed,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PaginatedResponseSchema, usePlaybackQuery } from \"@behindthemusictree/app-kit/transport\";\nimport TrackItem from \"../track-list-sidebar/TrackItem\";\n\nconst SongPageSchema = PaginatedResponseSchema(SongDetailedSchema);\n\nconst SORTS = [\n { ordering: \"title\", label: \"Title\" },\n { ordering: \"-albumYear\", label: \"Year\" },\n] as const;\ntype Ordering = (typeof SORTS)[number][\"ordering\"];\n\ninterface ArtistSongsProps {\n artist: { uuid: string; name: string };\n getBackendBaseUrl: () => string;\n renderArtistLink: RenderArtistLink;\n renderSongLink?: RenderSongLink;\n}\n\nexport default function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }: ArtistSongsProps) {\n const [page, setPage] = useState(1);\n const [ordering, setOrdering] = useState<Ordering>(\"title\");\n const { playNewTrackListFromArtist } = useTrackList<SongDetailed>();\n const { playerTrackObject } = usePlayer();\n const { data, isPending, isError } = usePlaybackQuery({\n getBackendBaseUrl,\n queryKey: [\"referenceSongs\", \"artist\", artist.uuid, ordering, page],\n queryFn: (fetchBound) =>\n fetchBound(libraryEndpoints.reference.songs.list(), true, false, undefined, {\n artist: artist.uuid,\n ordering,\n page,\n }),\n schema: SongPageSchema,\n placeholderData: keepPreviousData,\n context: \"ArtistSongs\",\n });\n\n const play = (startSongUuid?: string) =>\n playNewTrackListFromArtist({ uuid: artist.uuid, name: artist.name }, \"reference\", {\n ordering,\n startSongUuid,\n });\n\n // TrackItem's own play control (`.track-position-play-pause`, a div) plays from whatever list is active; a click on a track that isn't\n // loaded yet must queue this artist's list instead.\n const handleRowClickCapture = (event: MouseEvent, song: SongDetailed) => {\n if (!(event.target instanceof Element) || !event.target.closest(\".track-position-play-pause\")) return;\n if (playerTrackObject?.track.id === song.uuid || songUnplayableReason(song) !== null) return;\n event.stopPropagation();\n void play(song.uuid);\n };\n\n return (\n <PanelSection title=\"Songs\">\n {isPending ? (\n <Skeleton className=\"h-14\" aria-busy=\"true\" />\n ) : isError ? (\n <p className=\"text-red-600\">Could not load songs.</p>\n ) : data.results.length === 0 ? (\n <p className=\"text-[var(--color-text-muted)]\">No songs yet.</p>\n ) : (\n <>\n <div className=\"flex flex-wrap items-center justify-end gap-2 mb-2\">\n <div role=\"group\" aria-label=\"Sort songs by\" className=\"flex gap-1 text-caption\">\n {SORTS.map((sort) => (\n <button\n key={sort.ordering}\n type=\"button\"\n aria-pressed={ordering === sort.ordering}\n onClick={() => {\n setOrdering(sort.ordering);\n setPage(1);\n }}\n className=\"px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white\"\n >\n {sort.label}\n </button>\n ))}\n </div>\n </div>\n <ul className=\"overflow-hidden mb-2 bg-zinc-950 rounded-lg\">\n {data.results.map((song, index) => (\n <li key={song.uuid} onClickCapture={(event) => handleRowClickCapture(event, song)}>\n <TrackItem\n track={song}\n position={(page - 1) * data.pageSize + index + 1}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n </li>\n ))}\n </ul>\n <Pagination currentPage={page} totalPages={data.totalPages} onPageChange={setPage} />\n </>\n )}\n </PanelSection>\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport { useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport TrackPositionPlayPause from \"../TrackPositionPlayPause\";\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { isSong, songUnplayableReason } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { MusicBrainzRecordingLink } from \"../MusicBrainzRecordingLink\";\nimport type { RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { ArtistNames, RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport interface TrackItemProps<T extends TrackBase> {\n track: T;\n position: number;\n renderDuration?: (track: T) => ReactNode;\n renderActions?: (track: T) => ReactNode;\n /** When set, artist names render through it (e.g. a router `Link`). */\n renderArtistLink?: RenderArtistLink;\n /** When set, a song title renders through it (e.g. opens the song panel) instead of linking to MusicBrainz. */\n renderSongLink?: RenderSongLink;\n}\n\nexport default function TrackItem<T extends TrackBase>({\n track,\n position,\n renderDuration,\n renderActions,\n renderArtistLink,\n renderSongLink,\n}: TrackItemProps<T>) {\n const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = usePlayer();\n const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = useTrackList<T>();\n const scope = trackList?.origin?.scope ?? null;\n const isCurrentTrack = playerTrackObject?.track.id === track.uuid;\n const hasPlaybackError = isCurrentTrack && !!playerTrackObject?.loadError;\n const isUnplayable =\n hasPlaybackError ||\n runtimeUnplayableTrackIds?.has(track.uuid) === true ||\n (isSong(track) && songUnplayableReason(track) !== null);\n\n const handlePlayPauseClick = (event: React.MouseEvent) => {\n event.stopPropagation();\n if (isCurrentTrack) {\n handlePlayPauseAction();\n } else if (scope != null) {\n toTrackAtPosition(position);\n loadTrackForPlayer(track.uuid);\n }\n };\n\n return (\n <div\n className={`track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? \"opacity-50\" : \"hover:bg-[var(--color-surface-muted)] group\"}`}\n >\n {isUnplayable ? (\n <div\n className=\"flex items-center justify-center text-lg w-16\"\n style={{ minWidth: \"4rem\", maxWidth: \"4rem\" }}\n aria-disabled=\"true\"\n >\n {position}\n </div>\n ) : (\n <TrackPositionPlayPause\n position={position}\n uuid={track.uuid}\n handlePlayPauseClick={handlePlayPauseClick}\n isSelected={selectedTrack?.uuid === track.uuid}\n />\n )}\n <div className=\"title-artist-container flex flex-col items-start justify-center min-w-0 flex-1\">\n <div className=\"flex max-w-full items-center gap-2\">\n <div className=\"title text-lg font-bold text-[var(--color-text)] max-w-full truncate\">\n {renderSongLink ? (\n renderSongLink(track)\n ) : isSong(track) ? (\n <MusicBrainzRecordingLink song={track} className=\"hover:underline focus-visible:underline\">\n {track.title}\n </MusicBrainzRecordingLink>\n ) : (\n track.title\n )}\n </div>\n </div>\n {track.artists && track.artists.length > 0 ? (\n <div className=\"artist text-base max-w-full truncate text-[var(--color-text-muted)]\">\n <ArtistNames artists={track.artists} renderArtistLink={renderArtistLink} />\n </div>\n ) : (\n \"\"\n )}\n </div>\n <div className=\"genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0\">\n {track.genre ? (\n <div className=\"genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold\">{track.genre.name}</div>\n ) : (\n \"\"\n )}\n </div>\n {renderDuration && (\n <div\n className=\"duration flex text-base w-16 items-center justify-center\"\n style={{ minWidth: \"4rem\", maxWidth: \"4rem\" }}\n >\n {renderDuration(track)}\n </div>\n )}\n {renderActions && (\n <div className=\"edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer\">\n {renderActions(track)}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { FaPlay, FaPause } from \"react-icons/fa\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport { PlayStates } from \"@behindthemusictree/app-kit/player\";\n\nexport interface TrackPositionPlayPauseProps {\n position: number;\n uuid: string;\n handlePlayPauseClick: (event: React.MouseEvent) => void;\n isSelected?: boolean;\n}\n\nexport default function TrackPositionPlayPause({\n position,\n uuid,\n handlePlayPauseClick,\n isSelected = false,\n}: TrackPositionPlayPauseProps) {\n const { playerTrackObject, playbackConfirmedTrackId, playState, isLoading: isPlayerLoading } = usePlayer();\n const isThisTrack = playerTrackObject?.track.id === uuid;\n const isConfirmedPlayable = playbackConfirmedTrackId === uuid;\n const isAwaitingPlayback =\n (isSelected || isThisTrack) &&\n !isConfirmedPlayable &&\n !(isThisTrack && playerTrackObject?.loadError) &&\n (!isThisTrack || isPlayerLoading || playState === PlayStates.LOADING || playState === PlayStates.PLAYING);\n const isPlaying = isThisTrack && isConfirmedPlayable && playState === PlayStates.PLAYING;\n const isPaused = isThisTrack && isConfirmedPlayable && playState === PlayStates.PAUSED;\n const isCurrentTrackActive = isPlaying || isPaused;\n\n return (\n <div\n className=\"track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer\"\n style={{ minWidth: \"4rem\", maxWidth: \"4rem\" }}\n onClick={handlePlayPauseClick}\n >\n <div className=\"track-position-play-pause__status group-hover:hidden flex items-center justify-center\">\n {isAwaitingPlayback ? (\n <span className=\"track-position-play-pause__spinner\" role=\"status\" aria-label=\"Loading track\" />\n ) : isCurrentTrackActive ? (\n <span\n className=\"track-position-play-pause__bars\"\n data-playing={isPlaying}\n role=\"img\"\n aria-label={isPlaying ? \"Playing\" : \"Paused\"}\n >\n <span className=\"track-position-play-pause__bar\" />\n <span className=\"track-position-play-pause__bar\" />\n <span className=\"track-position-play-pause__bar\" />\n </span>\n ) : (\n position\n )}\n </div>\n <div\n className={`hidden group-hover:flex items-center justify-center ${\n isCurrentTrackActive ? \"\" : \"absolute inset-0\"\n }`}\n aria-hidden=\"true\"\n >\n {isAwaitingPlayback ? (\n <span className=\"track-position-play-pause__spinner\" />\n ) : isPlaying ? (\n <FaPause />\n ) : (\n <FaPlay />\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { Skeleton } from \"@behindthemusictree/ui\";\nimport {\n useSong,\n type CriteriaMinimum,\n type CriteriaPlaylistSimple,\n type RenderArtistLink,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { GetGenreTreeShareUrl } from \"../share\";\nimport SongPanelContent from \"./SongPanelContent\";\nimport type { OverlayPanel } from \"../overlayPanel\";\n\n/** How the song's genre is opened: through the loaded tree's playlists, or by the genre alone for a host without a tree. */\nexport type SongGenreNavigation =\n | {\n /** Root-to-leaf playlists of a genre in the loaded tree; empty when the tree doesn't hold it. */\n getGenrePath: (genre: CriteriaMinimum) => CriteriaPlaylistSimple[];\n onSelectGenrePlaylist: (genrePlaylist: CriteriaPlaylistSimple) => void;\n onSelectGenre?: never;\n }\n | {\n onSelectGenre: (genre: CriteriaMinimum) => void;\n getGenrePath?: never;\n onSelectGenrePlaylist?: never;\n };\n\nexport type SongPanelOptions = {\n uuid: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n renderArtistLink: RenderArtistLink;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n onClose: () => void;\n} & SongGenreNavigation;\n\n/** The song detail overlay panel for `uuid`, or undefined when no song is set. */\nexport function useSongPanel({\n uuid,\n scope,\n getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n expanded,\n onExpandedChange,\n onClose,\n ...navigation\n}: SongPanelOptions): OverlayPanel | undefined {\n const result = useSong(uuid, getBackendBaseUrl);\n\n const panel = { expanded, onExpandedChange, onClose };\n switch (result.status) {\n case \"idle\":\n return undefined;\n case \"loading\":\n return {\n ...panel,\n title: \"Song\",\n content: (\n <div aria-busy=\"true\" className=\"flex flex-col gap-2.5\">\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-24\" />\n </div>\n ),\n };\n case \"not-found\":\n return {\n ...panel,\n title: \"Song not found\",\n content: <p className=\"text-[var(--color-text-muted)]\">This song does not exist.</p>,\n };\n case \"error\":\n return {\n ...panel,\n title: \"Song\",\n content: <p className=\"text-red-600\">Could not load this song.</p>,\n };\n case \"success\": {\n const { song } = result;\n const shareUrl = getShareUrl?.({ kind: \"song\", uuid: song.uuid, name: song.title, scope });\n return {\n ...panel,\n title: song.title,\n content: (\n <SongPanelContent\n song={song}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n shareUrl={shareUrl ?? undefined}\n renderArtistLink={renderArtistLink}\n {...(navigation.getGenrePath\n ? {\n genrePath: song.genre ? navigation.getGenrePath(song.genre) : [],\n onSelectGenrePlaylist: navigation.onSelectGenrePlaylist,\n }\n : { onSelectGenre: navigation.onSelectGenre })}\n />\n ),\n };\n }\n }\n}\n","\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\nimport { Pause, Play } from \"lucide-react\";\nimport { ActionBand, ActionButton, FieldList, PANEL_LABEL_CLASS, PanelBleed, PanelSection, Skeleton } from \"@behindthemusictree/ui\";\nimport { PlayStates, usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport {\n ArtistNames,\n musicBrainzRecordingUrl,\n songUnplayableReason,\n useSongHistory,\n useTrackList,\n type CriteriaMinimum,\n type CriteriaPlaylistSimple,\n type RenderArtistLink,\n type SongDetailed,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport ShareActionButton from \"../ShareActionButton\";\nimport type { GenreTreeShareTarget } from \"../share\";\n\nexport type SongPanelContentProps = {\n song: SongDetailed;\n scope: Scope;\n getBackendBaseUrl: () => string;\n shareUrl?: string;\n renderArtistLink: RenderArtistLink;\n} & (\n | {\n /** Root-to-leaf playlists of the song's genre in the loaded tree; empty when the tree doesn't hold it. */\n genrePath: CriteriaPlaylistSimple[];\n onSelectGenrePlaylist: (genrePlaylist: CriteriaPlaylistSimple) => void;\n onSelectGenre?: never;\n }\n | {\n /** The genre alone opens, for a host without a tree. */\n onSelectGenre: (genre: CriteriaMinimum) => void;\n genrePath?: never;\n onSelectGenrePlaylist?: never;\n }\n);\n\nconst numberFormat = new Intl.NumberFormat(\"en\");\nconst dateFormat = new Intl.DateTimeFormat(\"en\", { dateStyle: \"medium\" });\n\nconst externalLink = \"text-[var(--color-primary)] hover:underline focus-visible:underline\";\n\nfunction SongHistory({ uuid, getBackendBaseUrl }: { uuid: string; getBackendBaseUrl: () => string }) {\n const [open, setOpen] = useState(false);\n const history = useSongHistory(uuid, getBackendBaseUrl, open);\n let body: ReactNode = null;\n if (history.status === \"loading\") body = <Skeleton className=\"h-10\" aria-busy=\"true\" />;\n else if (history.status === \"error\") body = <p className=\"text-red-600\">Could not load the history.</p>;\n else if (history.status === \"success\")\n body =\n history.entries.length === 0 ? (\n <p className=\"text-[var(--color-text-muted)]\">No changes yet.</p>\n ) : (\n <ul className=\"divide-y divide-[var(--color-border)]\">\n {history.entries.map((entry) => (\n <li key={entry.uuid} className=\"py-1.5 text-body\">\n <span className=\"font-medium\">{entry.action}</span>\n {entry.oldValue !== null || entry.newValue !== null ? (\n <span className=\"text-[var(--color-text-muted)]\">\n {\" \"}\n — {entry.oldValue ?? \"none\"} → {entry.newValue ?? \"none\"}\n </span>\n ) : null}\n <span className=\"block text-caption text-[var(--color-text-muted)]\">\n {entry.actorPseudo ?? \"Anonymous\"} · {dateFormat.format(new Date(entry.createdOn))}\n </span>\n </li>\n ))}\n </ul>\n );\n\n return (\n <PanelBleed padded className=\"border-t border-[var(--color-border)]\">\n <details onToggle={(event) => setOpen(event.currentTarget.open)} className=\"pb-2.5\">\n <summary className={`mt-2.5 cursor-pointer ${PANEL_LABEL_CLASS}`}>\n History\n </summary>\n <div className=\"mt-1.5\">{body}</div>\n </details>\n </PanelBleed>\n );\n}\n\nexport default function SongPanelContent(props: SongPanelContentProps) {\n const { song, scope, getBackendBaseUrl, shareUrl, renderArtistLink } = props;\n const { playNewTrackListFromTrackUuid } = useTrackList<SongDetailed>();\n const { playerTrackObject, playState, handlePlayPauseAction } = usePlayer();\n const unplayableReason = songUnplayableReason(song);\n const isCurrent = playerTrackObject?.track.id === song.uuid;\n const isPlaying = isCurrent && playState === PlayStates.PLAYING;\n const shareTarget: GenreTreeShareTarget = { kind: \"song\", uuid: song.uuid, name: song.title, scope };\n const musicBrainzUrl = musicBrainzRecordingUrl(song);\n\n const fields: { label: string; value: ReactNode }[] = [];\n if (song.genre) {\n const path = props.genrePath && props.genrePath.length > 0 ? props.genrePath : null;\n const { onSelectGenre } = props;\n const genre = song.genre;\n fields.push({\n label: \"Genre\",\n value: onSelectGenre ? (\n <button type=\"button\" onClick={() => onSelectGenre(genre)} className=\"hover:underline\">\n {genre.name}\n </button>\n ) : path ? (\n <span className=\"flex flex-wrap items-center gap-x-1\">\n {path.map((genrePlaylist, index) => (\n <span key={genrePlaylist.uuid}>\n {index > 0 && <span aria-hidden=\"true\">› </span>}\n <button type=\"button\" onClick={() => props.onSelectGenrePlaylist?.(genrePlaylist)} className=\"hover:underline\">\n {genrePlaylist.name}\n </button>\n </span>\n ))}\n </span>\n ) : (\n song.genre.name\n ),\n });\n } else {\n fields.push({ label: \"Genre\", value: <span className=\"text-[var(--color-text-muted)]\">No genre</span> });\n }\n if (song.firstReleaseYear) fields.push({ label: \"First released\", value: song.firstReleaseYear });\n const viewCount = song.youtubeVideo?.viewCount;\n if (viewCount !== null && viewCount !== undefined)\n fields.push({ label: \"YouTube views\", value: numberFormat.format(viewCount) });\n fields.push({ label: \"Plays\", value: numberFormat.format(song.playCount) });\n const links: ReactNode[] = [];\n if (musicBrainzUrl)\n links.push(\n <a key=\"mb\" href={musicBrainzUrl} target=\"_blank\" rel=\"noopener noreferrer\" className={externalLink}>\n MusicBrainz\n </a>,\n );\n if (song.youtubeVideo)\n links.push(\n <a\n key=\"yt\"\n href={`https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={externalLink}\n >\n YouTube\n </a>,\n );\n if (links.length > 0)\n fields.push({\n label: \"Links\",\n value: <span className=\"flex gap-3\">{links}</span>,\n });\n\n return (\n <>\n <PanelBleed>\n <ActionBand>\n <ActionButton\n icon={isPlaying ? <Pause aria-hidden=\"true\" className=\"w-5 h-5\" /> : <Play aria-hidden=\"true\" className=\"w-5 h-5\" />}\n label={isPlaying ? \"Pause\" : \"Play\"}\n disabled={!!unplayableReason}\n title={unplayableReason ?? undefined}\n onClick={() => (isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope))}\n />\n {shareUrl && <ShareActionButton target={shareTarget} url={shareUrl} />}\n </ActionBand>\n </PanelBleed>\n {song.artists && song.artists.length > 0 && (\n <p className=\"text-[var(--color-text-muted)]\">\n <ArtistNames artists={song.artists} renderArtistLink={renderArtistLink} />\n </p>\n )}\n <FieldList items={fields} />\n {song.essentialGenres && song.essentialGenres.length > 0 && (\n <PanelSection title=\"Essential in\">\n <ul>\n {song.essentialGenres.map((genre) => (\n <li key={genre.uuid} className=\"py-0.5\">\n {genre.name}\n </li>\n ))}\n </ul>\n </PanelSection>\n )}\n <SongHistory uuid={song.uuid} getBackendBaseUrl={getBackendBaseUrl} />\n </>\n );\n}\n","\"use client\";\n\nimport type { RenderArtistLink, RenderPlaceLink, RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useArtistPanel } from \"./artist/useArtistPanel\";\nimport { useSongPanel, type SongGenreNavigation } from \"./song/useSongPanel\";\nimport type { GetGenreTreeShareUrl } from \"./share\";\nimport type { OverlayPanel } from \"./overlayPanel\";\n\nexport interface EntityPanelState {\n uuid: string | null;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n onClose: () => void;\n}\n\nexport type EntityPanelOptions = {\n scope: Scope;\n getBackendBaseUrl: () => string;\n /** Artist requests go here when the host serves them from elsewhere; defaults to `getBackendBaseUrl`. */\n getArtistBackendBaseUrl?: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n renderArtistLink: RenderArtistLink;\n renderSongLink: RenderSongLink;\n renderPlaceLink?: RenderPlaceLink;\n song: EntityPanelState;\n artist: EntityPanelState;\n} & SongGenreNavigation;\n\n/** The song or artist detail overlay panel; a song takes precedence over an artist, undefined when neither is set. */\nexport function useEntityPanel({\n scope,\n getBackendBaseUrl,\n getArtistBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n song,\n artist,\n ...navigation\n}: EntityPanelOptions): OverlayPanel | undefined {\n const songPanel = useSongPanel({\n ...song,\n scope,\n getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n ...navigation,\n } as Parameters<typeof useSongPanel>[0]);\n const artistPanel = useArtistPanel({\n ...artist,\n scope,\n getBackendBaseUrl: getArtistBackendBaseUrl ?? getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n });\n return songPanel ?? artistPanel;\n}\n","\"use client\";\n\nimport { MdMusicNote, MdVisibility } from \"react-icons/md\";\nimport { SegmentedControl } from \"@behindthemusictree/ui\";\n\nimport type { GenreTreeSizeMetric } from \"./playlist-tree/size-metric\";\n\nexport function SizeMetricToggle({\n value,\n onChange,\n}: {\n value: GenreTreeSizeMetric;\n onChange: (value: GenreTreeSizeMetric) => void;\n}) {\n return (\n <SegmentedControl\n variant=\"floating\"\n aria-label=\"Size nodes by\"\n value={value}\n onChange={onChange}\n options={[\n { value: \"songs\", label: <MdMusicNote size={18} aria-hidden />, \"aria-label\": \"Size by songs\", title: \"Node size by song count\" },\n { value: \"views\", label: <MdVisibility size={18} aria-hidden />, \"aria-label\": \"Size by views\", title: \"Node size by song views\" },\n ]}\n />\n );\n}\n","export * from \"./GenreTreeView\";\nexport type { GenreTreeShareTarget, GetGenreTreeShareUrl } from \"./share\";\nexport type { ParentChange } from \"./ChangeParentPopup\";\nexport type { GenreDetailSlots } from \"./GenreDetailExtras\";\nexport { GenreDetailPanel } from \"./GenreDetailPanel\";\nexport type { GenreDetailPanelProps } from \"./GenreDetailPanel\";\nexport { GenreInfoPanelBody, GenreNodeActionBand } from \"./GenreInfoPanelBody\";\nexport type { GenreInfoPanelBodyProps, PlayableGenrePlaylist } from \"./GenreInfoPanelBody\";\nexport { useGenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\nexport type { GenrePlaylistPlayback, UseGenrePlaylistPlaybackOptions } from \"./playlist-tree/useGenrePlaylistPlayback\";\nexport type { GenrePlaylistTracksSlots } from \"./GenrePlaylistTracks\";\nexport { default as GenrePlaylistTreePerRoot } from \"./playlist-tree/TreePerRoot\";\nexport type { GenrePlaylistTreePerRootProps } from \"./playlist-tree/TreePerRoot\";\nexport { default as GenreSearch } from \"./GenreSearch\";\nexport type { GenreSearchProps, GenreSearchExtraGroup } from \"./GenreSearch\";\nexport * from \"./search\";\nexport {\n GenreTreeSkeleton,\n GenreTreeWheelSkeleton,\n GenreTreeViewSkeleton,\n GenreTreeOutlineSkeleton,\n} from \"@behindthemusictree/genre-tree-view\";\nexport type { GenreTreeAction, GenreTreeViewport, GenreTreeViewSkeletonProps } from \"@behindthemusictree/genre-tree-view\";\nexport { default as TrackListSidebar } from \"./track-list-sidebar/TrackListSidebar\";\nexport type { TrackListSidebarProps } from \"./track-list-sidebar/TrackListSidebar\";\nexport { default as PlayerPanel } from \"./PlayerPanel\";\nexport type { PlayerPanelProps } from \"./PlayerPanel\";\nexport { default as TrackItem } from \"./track-list-sidebar/TrackItem\";\nexport type { TrackItemProps } from \"./track-list-sidebar/TrackItem\";\nexport { default as TrackPositionPlayPause } from \"./TrackPositionPlayPause\";\nexport type { TrackPositionPlayPauseProps } from \"./TrackPositionPlayPause\";\nexport { default as Rating } from \"./Rating\";\nexport type { RatingProps } from \"./Rating\";\n\nexport type { GenreSearchGroupsProps } from \"./GenreTreeSearch\";\nexport { useEntityPanel } from \"./useEntityPanel\";\nexport type { EntityPanelOptions, EntityPanelState } from \"./useEntityPanel\";\nexport { EntityDetailPanel } from \"./EntityDetailPanel\";\nexport type { EntityDetailPanelProps } from \"./EntityDetailPanel\";\nexport type { SongGenreNavigation } from \"./song/useSongPanel\";\n","\"use client\";\n\nimport { ReactNode, useEffect, useLayoutEffect, useRef } from \"react\";\nimport { ListMusic } from \"lucide-react\";\n\nimport TrackItem from \"./TrackItem\";\nimport { useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { TrackListOriginType } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\n\nconst useBrowserLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\nexport interface TrackListSidebarProps<T extends TrackBase> {\n className?: string;\n renderDuration?: (track: T) => ReactNode;\n renderActions?: (track: T) => ReactNode;\n layout?: \"fixed\" | \"inline\";\n isCollapsed?: boolean;\n onExpand?: () => void;\n onMinimize?: () => void;\n /** When set, artist names render through it (e.g. a router `Link`). */\n renderArtistLink?: RenderArtistLink;\n /** When set, song titles render through it (e.g. open the song panel). */\n renderSongLink?: RenderSongLink;\n}\n\nexport default function TrackListSidebar<T extends TrackBase>({\n className = \"\",\n renderDuration,\n renderActions,\n layout = \"fixed\",\n isCollapsed = false,\n onExpand,\n onMinimize,\n renderArtistLink,\n renderSongLink,\n}: TrackListSidebarProps<T>) {\n const { trackList, loadMore, autoAdvanceScrollRequest } = useTrackList<T>();\n const trackNoun = useTrackNoun();\n const trackListRef = useRef<HTMLUListElement>(null);\n const previousOriginRef = useRef(trackList?.origin ?? null);\n const handledAutoAdvanceRequestIdRef = useRef<number | null>(null);\n const shouldFollowPlaybackRef = useRef(true);\n const programmaticScrollTopRef = useRef<number | null>(null);\n const userScrollIntentRef = useRef(false);\n const userScrollIntentTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const loadMoreSentinelRef = useRef<HTMLLIElement>(null);\n const hasMore = !!trackList && trackList.nextPage !== null;\n\n useEffect(() => {\n const sentinel = loadMoreSentinelRef.current;\n if (!hasMore || !sentinel) return;\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n loadMore().catch((error) => console.error(\"Failed to load more tracks:\", error));\n }\n });\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasMore, loadMore]);\n\n useBrowserLayoutEffect(() => {\n const origin = trackList?.origin ?? null;\n if (previousOriginRef.current === origin) return;\n previousOriginRef.current = origin;\n handledAutoAdvanceRequestIdRef.current = null;\n shouldFollowPlaybackRef.current = true;\n programmaticScrollTopRef.current = null;\n if (trackListRef.current) trackListRef.current.scrollTop = 0;\n }, [trackList?.origin]);\n\n useEffect(() => {\n const list = trackListRef.current;\n if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;\n }, [isCollapsed]);\n\n useEffect(\n () => () => {\n if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);\n },\n [],\n );\n\n useBrowserLayoutEffect(() => {\n if (\n !autoAdvanceScrollRequest ||\n handledAutoAdvanceRequestIdRef.current === autoAdvanceScrollRequest.id\n ) {\n return;\n }\n if (isCollapsed) return;\n\n const list = trackListRef.current;\n if (!list) return;\n if (list.scrollTop <= 1) shouldFollowPlaybackRef.current = true;\n if (!shouldFollowPlaybackRef.current) {\n handledAutoAdvanceRequestIdRef.current = autoAdvanceScrollRequest.id;\n return;\n }\n\n const row = Array.from(list.querySelectorAll<HTMLElement>(\"[data-track-uuid]\")).find(\n (element) => element.dataset.trackUuid === autoAdvanceScrollRequest.trackUuid,\n );\n if (!row) return;\n handledAutoAdvanceRequestIdRef.current = autoAdvanceScrollRequest.id;\n\n const rowTop = row.getBoundingClientRect().top - list.getBoundingClientRect().top;\n const targetScrollTop = list.scrollTop + rowTop;\n programmaticScrollTopRef.current = targetScrollTop;\n list.scrollTop = targetScrollTop;\n programmaticScrollTopRef.current = list.scrollTop;\n }, [autoAdvanceScrollRequest, isCollapsed, trackList]);\n\n const markUserScrollIntent = () => {\n userScrollIntentRef.current = true;\n if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);\n userScrollIntentTimerRef.current = setTimeout(() => {\n userScrollIntentRef.current = false;\n userScrollIntentTimerRef.current = null;\n }, 250);\n };\n\n const handleTrackListScroll = (event: React.UIEvent<HTMLUListElement>) => {\n const list = event.currentTarget;\n if (userScrollIntentRef.current) {\n userScrollIntentRef.current = false;\n if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);\n userScrollIntentTimerRef.current = null;\n programmaticScrollTopRef.current = null;\n shouldFollowPlaybackRef.current = list.scrollTop <= 1;\n return;\n }\n\n const programmaticScrollTop = programmaticScrollTopRef.current;\n if (programmaticScrollTop !== null) {\n if (Math.abs(list.scrollTop - programmaticScrollTop) <= 1) programmaticScrollTopRef.current = null;\n return;\n }\n };\n const positionClasses =\n layout === \"inline\"\n ? \"relative w-full flex h-full flex-col\"\n : \"fixed right-0 w-[50rem] flex flex-col\";\n\n return trackList ? (\n <div\n data-theme=\"dark\"\n className={`track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className}`}\n style={layout === \"fixed\" ? { top: \"63.5px\", maxHeight: \"calc(100vh - 63.5px - 79px)\" } : undefined}\n >\n <div className=\"header flex h-16 items-center px-4 py-2 text-[var(--color-text)]\">\n <div className=\"min-w-0 flex flex-1 flex-col justify-center\">\n <div className=\"origin flex text-xl\">\n <div className=\"from h-auto flex flex-col justify-center items-center mr-2\">From</div>\n <div className=\"name-container flex flex-col justify-center items-center text-[var(--color-text)] font-bold pr-2 max-w-[27.5rem]\">\n <div className=\"name max-w-full truncate\">{trackList.origin.label}</div>\n </div>\n </div>\n <div className=\"info flex items-center text-body text-[var(--color-text-muted)]\">\n {trackList.origin.type === TrackListOriginType.GENRE_PLAYLIST\n ? \"Genre • \"\n : trackList.origin.type === TrackListOriginType.ARTIST\n ? \"Artist • \"\n : `${trackNoun.singular} playlist • `}\n {`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`}\n </div>\n </div>\n {((isCollapsed && onExpand) || (!isCollapsed && onMinimize)) && (\n <button\n type=\"button\"\n aria-label={isCollapsed ? \"Show tracks\" : \"Hide tracks\"}\n title={isCollapsed ? \"Show tracks\" : \"Hide tracks\"}\n aria-expanded={!isCollapsed}\n className={`ml-2 flex h-8 w-8 shrink-0 items-center justify-center rounded-md hover:bg-[var(--color-surface-muted)] ${isCollapsed ? \"text-[var(--color-text-muted)]\" : \"text-white\"}`}\n onClick={isCollapsed ? onExpand : onMinimize}\n >\n <ListMusic aria-hidden=\"true\" className=\"h-5 w-5\" />\n </button>\n )}\n </div>\n {!isCollapsed && (\n <ul\n ref={trackListRef}\n onScroll={handleTrackListScroll}\n onWheel={markUserScrollIntent}\n onTouchMove={markUserScrollIntent}\n onPointerDown={markUserScrollIntent}\n className={\n layout === \"inline\"\n ? \"track-list flex-1 min-h-0 overflow-auto list-none p-0 m-0\"\n : \"track-list flex-1 min-h-0 overflow-auto list-none p-0 m-0\"\n }\n >\n {trackList.tracks.map((track, index) => (\n <li key={track.uuid} data-track-uuid={track.uuid}>\n <TrackItem\n track={track}\n position={index + 1}\n renderDuration={renderDuration}\n renderActions={renderActions}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n </li>\n ))}\n {hasMore && <li ref={loadMoreSentinelRef} aria-hidden=\"true\" className=\"h-px\" />}\n </ul>\n )}\n </div>\n ) : null;\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { twMerge } from \"tailwind-merge\";\nimport {\n usePlayer,\n PlayerVideoSurface,\n} from \"@behindthemusictree/app-kit/player\";\nimport {\n useTrackListSidebarVisibility,\n type RenderArtistLink,\n type RenderSongLink,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PanelEdgeTab } from \"@behindthemusictree/ui\";\nimport PlayerControls from \"./PlayerControls\";\nimport TrackListSidebar from \"./track-list-sidebar/TrackListSidebar\";\n\nexport interface PlayerPanelProps {\n className?: string;\n /** Hidden via CSS, never unmounted, so the video keeps playing while the host hides the panel. */\n isVisible?: boolean;\n /** @deprecated The player no longer closes; its header action minimizes to video-only mode. */\n onClose?: () => void;\n /** Controlled extended state; uncontrolled when omitted. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** Width once extended, e.g. to stop short of a left-hand detail panel. */\n extendedWidth?: string;\n renderArtistLink?: RenderArtistLink;\n /** When set, song titles in the tracklist render through it (e.g. open the song panel). */\n renderSongLink?: RenderSongLink;\n}\n\nconst PANEL_ID = \"player-panel\";\n\n// Spans the center and right columns.\nconst DEFAULT_EXTENDED_WIDTH =\n \"calc(100vw - var(--layout-center-left) - var(--layout-gutter))\";\n\nexport default function PlayerPanel({\n className,\n isVisible = true,\n expanded,\n onExpandedChange,\n extendedWidth = DEFAULT_EXTENDED_WIDTH,\n renderArtistLink,\n renderSongLink,\n}: PlayerPanelProps) {\n const { playerTrackObject, retryPlayback } = usePlayer();\n const { toggleTrackListSidebar, isTrackListSidebarVisible } =\n useTrackListSidebarVisibility();\n const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = useState(\"\");\n const loadedTrackTitle = playerTrackObject?.track.title;\n useEffect(() => {\n if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);\n }, [loadedTrackTitle]);\n const [uncontrolledExtended, setUncontrolledExtended] = useState(false);\n const isExtendRequested = expanded ?? uncontrolledExtended;\n const setIsExtendRequested = (next: boolean) => {\n setUncontrolledExtended(next);\n onExpandedChange?.(next);\n };\n const isExtended = isExtendRequested && isTrackListSidebarVisible;\n const hideSongList = () => {\n setIsExtendRequested(false);\n if (isTrackListSidebarVisible) toggleTrackListSidebar();\n };\n\n const tabEdge =\n isTrackListSidebarVisible && isExtended\n ? {\n label: \"Shrink player panel\",\n onClick: () => setIsExtendRequested(false),\n expanded: true,\n }\n : null;\n const tabCenter =\n isTrackListSidebarVisible && !isExtended\n ? {\n label: \"Extend player panel\",\n onClick: () => setIsExtendRequested(true),\n expanded: false,\n }\n : null;\n\n return (\n <div\n id={PANEL_ID}\n className={twMerge(\n \"fixed right-[var(--layout-gutter)] top-[var(--layout-band-top)] z-40 max-h-[calc(100vh-var(--layout-band-top)-3.5rem)]\",\n !isExtended && \"w-[var(--layout-right-w)]\",\n isTrackListSidebarVisible &&\n \"h-[calc(100vh-var(--layout-band-top)-3.5rem)]\",\n !isVisible && \"hidden\",\n className,\n )}\n style={isExtended ? { width: extendedWidth } : undefined}\n >\n <PanelEdgeTab\n side=\"right\"\n edge={tabEdge}\n center={tabCenter}\n controls={PANEL_ID}\n className=\"absolute right-full top-1/2 -translate-y-1/2\"\n />\n <div\n className={twMerge(\n \"flex h-full max-h-[inherit] overflow-hidden rounded-[var(--radius-panel,1rem)] bg-zinc-950 text-zinc-100 shadow-[0_1px_2px_rgba(0,0,0,0.5),0_2px_6px_2px_rgba(0,0,0,0.3)]\",\n isExtended ? \"flex-row\" : \"flex-col\",\n )}\n >\n <div className=\"flex w-[var(--layout-right-w)] shrink-0 flex-col\">\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2\">\n <span className=\"min-w-0 truncate text-sm font-semibold\">\n {loadedTrackTitle || lastLoadedTrackTitle}\n </span>\n </div>\n <div className=\"relative w-full shrink-0\">\n <PlayerVideoSurface className=\"aspect-video w-full bg-black\" />\n {playerTrackObject?.loadError && (\n <span className=\"absolute bottom-2 left-2 right-2 text-xs text-red-400\">\n {playerTrackObject.loadError}\n <button type=\"button\" className=\"ml-2 underline\" onClick={() => { void retryPlayback(); }}>Retry</button>\n </span>\n )}\n </div>\n <PlayerControls />\n </div>\n <TrackListSidebar\n layout=\"inline\"\n isCollapsed={!isTrackListSidebarVisible}\n onExpand={toggleTrackListSidebar}\n onMinimize={hideSongList}\n className={twMerge(\n \"min-h-0 min-w-0 flex-1\",\n isExtended && \"border-l border-zinc-800\",\n )}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { Pause, Play, SkipBack, SkipForward, Volume2, VolumeX } from \"lucide-react\";\nimport { formatTime, useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PlayStates, useCurrentTime, usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nexport default function PlayerControls() {\n const {\n duration,\n handlePlayPauseAction,\n isLoading,\n playState,\n playerTrackObject,\n seekTo,\n setVolume,\n volume,\n } = usePlayer();\n const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = useTrackList();\n const currentTime = useCurrentTime();\n const isBusy = isLoading || playState === PlayStates.LOADING;\n const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;\n const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;\n const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;\n const isPlaying = playState === PlayStates.PLAYING;\n\n return (\n <section\n aria-label=\"Player controls\"\n className=\"player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200\"\n >\n <div className=\"flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400\">\n <span aria-label=\"Elapsed time\">{formatTime(safeCurrentTime)}</span>\n <input\n aria-label=\"Seek\"\n className=\"h-1 min-w-0 flex-1 cursor-pointer accent-white disabled:cursor-not-allowed disabled:opacity-40\"\n type=\"range\"\n min={0}\n max={safeDuration}\n step={0.1}\n value={safeCurrentTime}\n disabled={!isReady || safeDuration <= 0}\n onChange={(event) => seekTo(Number(event.currentTarget.value))}\n />\n <span aria-label=\"Duration\">{formatTime(safeDuration)}</span>\n </div>\n\n <div className=\"grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3\">\n <div className=\"col-start-2 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n aria-label=\"Previous track\"\n title=\"Previous track\"\n disabled={!isReady || !hasPreviousTrack}\n onClick={playPreviousTrack}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <SkipBack aria-hidden=\"true\" className=\"h-4 w-4\" />\n </button>\n <button\n type=\"button\"\n aria-label={isPlaying ? \"Pause\" : \"Play\"}\n title={isPlaying ? \"Pause\" : \"Play\"}\n disabled={!isReady}\n onClick={handlePlayPauseAction}\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-white text-zinc-950 hover:bg-zinc-200 disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {isPlaying ? (\n <Pause aria-hidden=\"true\" className=\"h-4 w-4\" fill=\"currentColor\" />\n ) : (\n <Play aria-hidden=\"true\" className=\"h-4 w-4\" fill=\"currentColor\" />\n )}\n </button>\n <button\n type=\"button\"\n aria-label=\"Next track\"\n title=\"Next track\"\n disabled={!isReady || !hasNextTrack}\n onClick={playNextTrack}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <SkipForward aria-hidden=\"true\" className=\"h-4 w-4\" />\n </button>\n </div>\n\n <label className=\"col-start-3 flex w-[4.2rem] shrink-0 items-center gap-[0.35rem] justify-self-end text-zinc-400 sm:w-[4.9rem]\">\n {volume === 0 ? (\n <VolumeX aria-hidden=\"true\" className=\"h-[0.7rem] w-[0.7rem] shrink-0\" />\n ) : (\n <Volume2 aria-hidden=\"true\" className=\"h-[0.7rem] w-[0.7rem] shrink-0\" />\n )}\n <span className=\"sr-only\">Volume</span>\n <input\n aria-label=\"Volume\"\n className=\"h-[3px] min-w-0 flex-1 cursor-pointer accent-white disabled:cursor-not-allowed disabled:opacity-40\"\n type=\"range\"\n min={0}\n max={100}\n step={1}\n value={volume}\n disabled={!isReady}\n onChange={(event) => setVolume(Number(event.currentTarget.value))}\n />\n </label>\n </div>\n </section>\n );\n}\n","\"use client\";\n\nimport { v4 as uuidv4 } from \"uuid\";\nimport { AiFillStar, AiOutlineStar } from \"react-icons/ai\";\n\nimport { FORM_RATING_NULL_VALUE } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport interface RatingProps {\n rating: number | null | undefined;\n handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\nexport default function Rating({ rating, handleChange }: RatingProps) {\n const instanceId = uuidv4();\n return (\n <div className=\"flex items-center\">\n {[...Array(6)].map((_, i) => (\n <div key={i} className={`relative ${i === 0 ? \"mr-4\" : \"mr-1\"}`}>\n <input\n id={`star-${instanceId}-${i}`}\n className=\"w-6 h-6 opacity-0\"\n type=\"radio\"\n name=\"rating\"\n value={i === 0 ? FORM_RATING_NULL_VALUE : i}\n checked={rating === (i === 0 ? null : i)}\n onChange={handleChange}\n />\n <label htmlFor={`star-${instanceId}-${i}`} className=\"cursor-pointer\">\n {i === 0 ? (\n <div className=\"flex\">\n <AiOutlineStar\n className={`w-7 h-7 absolute top-0 left-0 ${\n rating === FORM_RATING_NULL_VALUE ? \"text-[var(--color-accent-rating)]\" : \"text-[var(--color-text-muted)]\"\n }`}\n />\n <span className=\"flex-grow w-8\"></span>{\" \"}\n </div>\n ) : (\n <AiFillStar\n className={`w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? \"text-[var(--color-accent-rating)]\" : \"text-[var(--color-text-muted)]\"}`}\n />\n )}\n </label>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, type ComponentProps } from \"react\";\nimport { DetailPanel } from \"@behindthemusictree/ui\";\nimport type { RenderArtistLink, RenderPlaceLink, RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useEntityPanel } from \"./useEntityPanel\";\nimport type { SongGenreNavigation } from \"./song/useSongPanel\";\nimport type { GetGenreTreeShareUrl } from \"./share\";\n\nexport type EntityDetailPanelProps = {\n scope: Scope;\n getBackendBaseUrl: () => string;\n getArtistBackendBaseUrl?: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n songUuid: string | null;\n onSongUuidChange: (uuid: string | null) => void;\n artistUuid: string | null;\n onArtistUuidChange: (uuid: string | null) => void;\n /** Names render as buttons that open the artist by default. */\n renderArtistLink?: RenderArtistLink;\n /** Titles render as buttons that open the song by default. */\n renderSongLink?: RenderSongLink;\n renderPlaceLink?: RenderPlaceLink;\n collapsed?: boolean;\n edgeTab?: ComponentProps<typeof DetailPanel>[\"edgeTab\"];\n} & SongGenreNavigation;\n\n/** The song or artist detail in the shared left DetailPanel, for a host that has no genre tree. Renders nothing\n * while neither is set; a song takes precedence over an artist. */\nexport function EntityDetailPanel({\n scope,\n getBackendBaseUrl,\n getArtistBackendBaseUrl,\n getShareUrl,\n songUuid,\n onSongUuidChange,\n artistUuid,\n onArtistUuidChange,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n collapsed,\n edgeTab,\n ...navigation\n}: EntityDetailPanelProps) {\n // Keyed by uuid, so switching entities (including a host's back/forward) starts compact.\n const [expandedSongUuid, setExpandedSongUuid] = useState<string | null>(null);\n const [expandedArtistUuid, setExpandedArtistUuid] = useState<string | null>(null);\n\n const panel = useEntityPanel({\n scope,\n getBackendBaseUrl,\n getArtistBackendBaseUrl,\n getShareUrl,\n renderPlaceLink,\n renderArtistLink:\n renderArtistLink ??\n ((artist) =>\n artist.isSpecialPurpose ? (\n artist.name\n ) : (\n <button type=\"button\" onClick={() => onArtistUuidChange(artist.uuid)} className=\"hover:underline\">\n {artist.name}\n </button>\n )),\n renderSongLink:\n renderSongLink ??\n ((song) => (\n <button type=\"button\" onClick={() => onSongUuidChange(song.uuid)} className=\"hover:underline\">\n {song.title}\n </button>\n )),\n song: {\n uuid: songUuid,\n expanded: songUuid !== null && expandedSongUuid === songUuid,\n onExpandedChange: (on) => setExpandedSongUuid(on ? songUuid : null),\n onClose: () => onSongUuidChange(null),\n },\n artist: {\n uuid: artistUuid,\n expanded: artistUuid !== null && expandedArtistUuid === artistUuid,\n onExpandedChange: (on) => setExpandedArtistUuid(on ? artistUuid : null),\n onClose: () => onArtistUuidChange(null),\n },\n ...navigation,\n } as Parameters<typeof useEntityPanel>[0]);\n if (!panel) return null;\n\n return (\n <DetailPanel\n side=\"left\"\n title={panel.title}\n titleInSearch\n onClose={panel.onClose}\n collapsed={collapsed}\n expanded={panel.expanded}\n onExpandedChange={panel.onExpandedChange}\n aside={panel.extraContent}\n edgeTab={edgeTab}\n >\n {panel.extraContent && !panel.expanded ? (\n <>\n {panel.content}\n {panel.extraContent}\n </>\n ) : (\n panel.content\n )}\n </DetailPanel>\n );\n}\n"],"mappings":"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","names":["className","import_jsx_runtime","className","import_ui","import_jsx_runtime","className","import_react","import_react_dom","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_ui","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_lucide_react","import_ui","import_jsx_runtime","import_fa","import_ui","import_lucide_react","import_transport","import_jsx_runtime","import_jsx_runtime","import_react","import_react_query","import_lucide_react","import_ui","import_genre_tree_view","import_genre_tree","import_popup","import_genre_tree","import_react","import_react","import_genre_tree","import_popup","import_transport","import_jsx_runtime","import_jsx_runtime","className","import_genre_tree","import_react","import_genre_tree_view","import_player","import_jsx_runtime","className","import_genre_tree","import_react","import_genre_tree_view","import_player","import_jsx_runtime","className","import_react","import_jsx_runtime","import_react","import_lucide_react","import_ui","import_genre_tree","import_react","import_ui","import_jsx_runtime","className","import_genre_tree","import_jsx_runtime","import_genre_tree","import_jsx_runtime","import_genre_tree","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_genre_tree_view","import_ui","import_lucide_react","import_genre_tree","import_genre_tree","import_lucide_react","import_ui","import_lucide_react","import_ui","import_popup","import_react","import_lucide_react","import_fa","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_ui","import_genre_tree","import_player","import_react","import_jsx_runtime","className","import_jsx_runtime","className","import_jsx_runtime","import_ui","import_genre_tree","import_react","import_jsx_runtime","className","import_jsx_runtime","import_react","import_fa","import_ui","import_auth","import_transport","import_player","import_popup","import_transport","import_genre_tree","import_genre_tree","import_jsx_runtime","className","import_genre_tree","import_track_noun","import_jsx_runtime","artist","import_track_noun","import_si","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","ancestors","import_react","import_genre_tree","import_jsx_runtime","import_ui","import_genre_tree","import_lucide_react","import_ui","import_genre_tree","import_player","import_jsx_runtime","import_ui","import_lucide_react","import_si","import_ui","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_ui","import_jsx_runtime","import_ui","import_jsx_runtime","import_react","import_react_query","import_ui","import_player","import_genre_tree","import_transport","import_player","import_genre_tree","import_fa","import_player","import_jsx_runtime","import_genre_tree","import_genre_tree","import_jsx_runtime","import_jsx_runtime","SongPageSchema","import_jsx_runtime","import_ui","import_genre_tree","import_react","import_lucide_react","import_ui","import_player","import_genre_tree","import_jsx_runtime","import_jsx_runtime","import_md","import_ui","import_jsx_runtime","import_jsx_runtime","className","genrePlaylist","import_genre_tree_view","import_react","import_lucide_react","import_genre_tree","import_track_noun","import_jsx_runtime","className","import_react","import_player","import_genre_tree","import_ui","import_lucide_react","import_genre_tree","import_player","import_jsx_runtime","import_jsx_runtime","className","import_genre_tree","import_jsx_runtime","uuidv4","import_react","import_ui","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/popup/PopupTitle.tsx","../src/popup/PopupButtons.tsx","../src/popup/BasePopup.tsx","../src/popup/Toast.tsx","../src/popup/TrackUploadPopup.tsx","../src/popup/AuthErrorPopup.tsx","../src/popup/InternalErrorPopup.tsx","../src/popup/NetworkErrorPopup.tsx","../src/popup/AuthPopup.tsx","../src/popup/SpotifyAuthErrorPopup.tsx","../src/auth/AuthCallbackHandler.tsx","../src/genre-tree/GenreTreeView.tsx","../src/genre-tree/playlist-tree/size-metric.ts","../src/genre-tree/playlist-tree/toTreeNodes.ts","../src/genre-tree/playlist-tree/toGenreNodeStyles.ts","../src/genre-tree/playlist-tree/TreePerRoot.tsx","../src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx","../src/genre-tree/playlist-tree/TreeWheel.tsx","../src/genre-tree/playlist-tree/TreeWheelRadialPopCore.tsx","../src/genre-tree/GenreTreeWheelHandoff.tsx","../src/genre-tree/GenreTreeSearch.tsx","../src/genre-tree/GenreSearch.tsx","../src/genre-tree/search/SearchBox.tsx","../src/genre-tree/search/SearchGroup.ts","../src/genre-tree/search/useArtistSearchGroup.tsx","../src/genre-tree/search/useSongSearchGroup.tsx","../src/genre-tree/search/useGenreRemoteSearchGroup.tsx","../src/genre-tree/GenreDetailPanel.tsx","../src/genre-tree/GenreInfoPanelBody.tsx","../src/genre-tree/GenreActionBand.tsx","../src/genre-tree/ShareActionButton.tsx","../src/genre-tree/SharePopup.tsx","../src/genre-tree/ShareDestinationButton.tsx","../src/genre-tree/SharePreviewCard.tsx","../src/genre-tree/GenrePlayActions.tsx","../src/genre-tree/RegionGlobeIcon.tsx","../src/genre-tree/regionGlobePaths.ts","../src/genre-tree/treeMarkPath.ts","../src/genre-tree/TreeMarkIcon.tsx","../src/genre-tree/GenreDetailExtras.tsx","../src/genre-tree/ClampedText.tsx","../src/genre-tree/CommonsPhoto.tsx","../src/genre-tree/GenrePlaylistTracks.tsx","../src/genre-tree/MusicBrainzRecordingLink.tsx","../src/genre-tree/ChangeParentPopup.tsx","../src/genre-tree/artist/useArtistPanel.tsx","../src/genre-tree/artist/ArtistActionBand.tsx","../src/genre-tree/artist/ArtistHeader.tsx","../src/genre-tree/artist/ArtistLinks.tsx","../src/genre-tree/artist/formatYears.ts","../src/genre-tree/artist/ArtistPhoto.tsx","../src/genre-tree/artist/ArtistMembers.tsx","../src/genre-tree/artist/ArtistDiscography.tsx","../src/genre-tree/artist/ArtistSongs.tsx","../src/genre-tree/track-list-sidebar/TrackItem.tsx","../src/genre-tree/TrackPositionPlayPause.tsx","../src/genre-tree/song/useSongPanel.tsx","../src/genre-tree/song/SongPanelContent.tsx","../src/genre-tree/useEntityPanel.tsx","../src/genre-tree/SizeMetricToggle.tsx","../src/genre-tree/index.ts","../src/genre-tree/track-list-sidebar/TrackListSidebar.tsx","../src/genre-tree/PlayerPanel.tsx","../src/genre-tree/PlayerControls.tsx","../src/genre-tree/Rating.tsx","../src/genre-tree/EntityDetailPanel.tsx"],"sourcesContent":["export * from \"./popup\";\nexport * from \"./auth\";\nexport * from \"./genre-tree\";\n","\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\ninterface PopupTitleProps {\n title: string;\n onClose: () => void;\n isDismissable?: boolean;\n icon?: LucideIcon;\n className?: string;\n titleClassName?: string;\n closeButtonClassName?: string;\n}\n\nexport function PopupTitle({\n title,\n onClose,\n isDismissable,\n icon: Icon,\n className = \"\",\n titleClassName = \"\",\n closeButtonClassName = \"\",\n}: PopupTitleProps) {\n return (\n <div className={`popup-title flex items-center justify-between bg-black p-4 rounded-t-lg ${className}`}>\n <div className=\"flex items-center gap-2\">\n {Icon && <Icon className=\"h-5 w-5 text-white\" />}\n <h3 id=\"popup-title\" className={`text-white font-semibold ${titleClassName}`}>\n {title}\n </h3>\n </div>\n {isDismissable && (\n <Button\n onClick={onClose}\n className={`h-8 w-8 text-white hover:text-white/80 ${closeButtonClassName}`}\n aria-label=\"Close popup\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\n\ninterface PopupButtonsProps {\n children: ReactNode;\n alignment?: \"left\" | \"center\" | \"right\";\n className?: string;\n}\n\nexport function PopupButtons({ children, alignment = \"center\", className = \"\" }: PopupButtonsProps) {\n const alignmentClasses = {\n left: \"justify-start\",\n center: \"justify-center\",\n right: \"justify-end\",\n };\n\n return <div className={`flex gap-3 ${alignmentClasses[alignment]} ${className}`}>{children}</div>;\n}\n","\"use client\";\n\nimport { createPortal } from \"react-dom\";\nimport { ReactNode, useEffect, useRef } from \"react\";\nimport { PopupTitle } from \"./PopupTitle\";\nimport { PopupButtons } from \"./PopupButtons\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\nexport interface BasePopupProps {\n title: string;\n children: ReactNode;\n onClose?: () => void;\n type?: \"default\" | \"success\" | \"error\" | \"warning\" | \"info\" | \"spotify\" | \"auth\";\n icon?: LucideIcon;\n isDismissable?: boolean;\n className?: string;\n overlayClassName?: string;\n titleClassName?: string;\n titleTextClassName?: string;\n closeButtonClassName?: string;\n /** Sizes the popup to its content (up to the type's max width) instead of filling it. */\n fitContent?: boolean;\n contentClassName?: string;\n showOkButton?: boolean;\n showCancelButton?: boolean;\n okButtonText?: string;\n okButtonDisabled?: boolean;\n cancelButtonText?: string;\n onOk?: () => void;\n onCancel?: () => void;\n buttonAlignment?: \"left\" | \"center\" | \"right\";\n /**\n * Distance (in px) reserved at the top of the viewport, e.g. for a fixed app header/banner.\n * Each consuming app passes its own value. Defaults to 0.\n */\n topOffset?: number;\n /** Keeps keyboard focus within the popup and restores it to the opener when dismissed. */\n trapFocus?: boolean;\n /** Closes a dismissable popup on Escape. */\n closeOnEscape?: boolean;\n /** Closes a dismissable popup when the backdrop is clicked. */\n closeOnBackdrop?: boolean;\n}\n\nconst typeClasses: Record<string, string> = {\n default: \"w-full max-w-lg\",\n success: \"w-full max-w-lg\",\n error: \"w-full max-w-lg\",\n warning: \"w-full max-w-lg\",\n info: \"w-full max-w-lg\",\n spotify: \"w-full max-w-md\",\n auth: \"w-full max-w-md\",\n};\n\nconst contentBgClasses: Record<string, string> = {\n spotify: \"bg-green-500\",\n auth: \"bg-gray-800\",\n};\n\nexport function BasePopup(props: BasePopupProps) {\n const {\n title,\n children,\n onClose,\n type = \"default\",\n icon,\n isDismissable = true,\n className,\n overlayClassName = \"\",\n titleClassName = \"\",\n titleTextClassName = \"\",\n closeButtonClassName = \"\",\n fitContent = false,\n contentClassName = \"\",\n showOkButton = false,\n showCancelButton = false,\n okButtonText = \"OK\",\n cancelButtonText = \"Cancel\",\n onOk,\n okButtonDisabled = false,\n onCancel,\n buttonAlignment = \"center\",\n topOffset = 0,\n trapFocus = false,\n closeOnEscape = false,\n closeOnBackdrop = false,\n } = props;\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const dialog = dialogRef.current;\n const focusableSelector =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const getFocusable = () =>\n Array.from(dialog?.querySelectorAll<HTMLElement>(focusableSelector) ?? []).filter(\n (element) => !element.hasAttribute(\"hidden\") && element.getAttribute(\"aria-hidden\") !== \"true\",\n );\n\n if (trapFocus) (getFocusable()[0] ?? dialog)?.focus();\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && closeOnEscape && isDismissable) {\n event.preventDefault();\n onClose?.();\n return;\n }\n if (!trapFocus || event.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n event.preventDefault();\n dialog?.focus();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (event.shiftKey && (document.activeElement === first || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (document.activeElement === last || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n first.focus();\n }\n };\n\n if (trapFocus || closeOnEscape) document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n if (trapFocus || closeOnEscape) document.removeEventListener(\"keydown\", handleKeyDown);\n if (trapFocus && previousFocus?.isConnected) previousFocus.focus();\n };\n }, [closeOnEscape, isDismissable, onClose, trapFocus]);\n\n const baseClasses = \"bg-white rounded-lg\";\n\n const renderButtons = () => {\n if (!showOkButton && !showCancelButton) return null;\n\n return (\n <div className=\"mt-4 pt-4 border-t\">\n <PopupButtons alignment={buttonAlignment}>\n {showCancelButton && (\n <Button onClick={onCancel || onClose || (() => {})} variant=\"secondary\">\n {cancelButtonText}\n </Button>\n )}\n {showOkButton && (\n <Button onClick={onOk || onClose || (() => {})} disabled={okButtonDisabled}>\n {okButtonText}\n </Button>\n )}\n </PopupButtons>\n </div>\n );\n };\n\n const popupComponent = (\n <div\n className={`fixed z-50 flex items-center justify-center bg-transparent ${overlayClassName}`}\n style={{\n top: topOffset,\n left: 0,\n right: 0,\n bottom: 0,\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"popup-title\"\n onClick={closeOnBackdrop && isDismissable ? onClose : undefined}\n >\n <div\n ref={dialogRef}\n tabIndex={trapFocus ? -1 : undefined}\n className={`${baseClasses} ${fitContent ? typeClasses[type].replace(\"w-full\", \"w-fit\") : typeClasses[type]} ${className || \"\"}`}\n onClick={(e) => e.stopPropagation()}\n >\n <PopupTitle\n title={title}\n onClose={onClose ?? (() => {})}\n isDismissable={isDismissable}\n icon={icon}\n className={titleClassName}\n titleClassName={titleTextClassName}\n closeButtonClassName={closeButtonClassName}\n />\n <div className={`popup-content rounded-b-lg p-4 ${contentBgClasses[type] ?? \"\"} ${contentClassName}`}>\n {children}\n {renderButtons()}\n </div>\n </div>\n </div>\n );\n\n return createPortal(popupComponent, document.body);\n}\n\nexport default BasePopup;\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport type ToastProps = {\n message: string;\n onClose: () => void;\n durationMs?: number;\n};\n\nexport default function Toast({ message, onClose, durationMs = 2200 }: ToastProps) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n const timeout = window.setTimeout(onClose, durationMs);\n return () => window.clearTimeout(timeout);\n }, [durationMs, onClose]);\n\n if (!mounted) return null;\n\n return createPortal(\n <div className=\"pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4\">\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-body text-[var(--color-text)] shadow-lg ring-1 ring-black/10\"\n >\n {message}\n </div>\n </div>,\n document.body,\n );\n}\n","\"use client\";\n\nimport { MdError, MdCheckCircle, MdUpload } from \"react-icons/md\";\nimport { useTrackUpload, type UploadStatus, type UseTrackUploadOptions } from \"@behindthemusictree/app-kit/popup\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { capitalize, useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\n\ntype TrackUploadPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> &\n UseTrackUploadOptions & {\n onClose?: () => void;\n };\n\nfunction getStatusIcon(status: UploadStatus) {\n switch (status) {\n case \"success\":\n return <MdCheckCircle className=\"text-[var(--color-green-500)]\" size={20} />;\n case \"error\":\n return <MdError className=\"text-[var(--color-red-500)]\" size={20} />;\n case \"uploading\":\n return <MdUpload className=\"text-[var(--color-blue-500)] animate-pulse\" size={20} />;\n default:\n return <div className=\"w-5 h-5 rounded-full border-2 border-[var(--color-neutral-300)]\" />;\n }\n}\n\nfunction getStatusText(status: UploadStatus) {\n switch (status) {\n case \"success\":\n return \"Uploaded\";\n case \"error\":\n return \"Failed\";\n case \"uploading\":\n return \"Uploading...\";\n default:\n return \"Pending\";\n }\n}\n\nexport default function TrackUploadPopup({\n files,\n genre,\n onProcessFile,\n onComplete,\n onClose,\n uploadTimeoutMs,\n ...rest\n}: TrackUploadPopupProps) {\n const { items, isUploading, allComplete, successfulCount, errorCount } = useTrackUpload({\n files,\n genre,\n onProcessFile,\n onComplete,\n uploadTimeoutMs,\n });\n\n const displayTotal = items.length > 0 ? items.length : files.length;\n const trackNoun = useTrackNoun();\n\n return (\n <BasePopup\n {...rest}\n onClose={onClose}\n title={`Upload ${capitalize(trackNoun.plural)} (${successfulCount}/${displayTotal})`}\n isDismissable\n showOkButton\n okButtonText=\"OK\"\n okButtonDisabled={isUploading || !allComplete}\n onOk={onClose}\n >\n <div className=\"space-y-4\">\n {items.map((item) => (\n <div key={item.id} className=\"border rounded-lg p-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"flex items-center space-x-3\">\n {getStatusIcon(item.status)}\n <div>\n <div className=\"font-medium text-body truncate max-w-xs\" title={item.file.name}>\n {item.file.name}\n </div>\n <div className=\"text-caption text-[var(--color-neutral-500)]\">{(item.file.size / 1024 / 1024).toFixed(1)} MB</div>\n </div>\n </div>\n <div className=\"text-body text-[var(--color-neutral-600)]\">{getStatusText(item.status)}</div>\n </div>\n\n {item.status === \"uploading\" && (\n <div className=\"w-full bg-[var(--color-neutral-200)] rounded-full h-2\">\n <div\n className=\"bg-[var(--color-blue-500)] h-2 rounded-full transition-all duration-300\"\n style={{ width: `${item.progress}%` }}\n />\n </div>\n )}\n\n {item.status === \"error\" && item.error && (\n <div className=\"text-[var(--color-red-500)] text-body mt-2\">\n {item.error.name === \"InvalidInputError\"\n ? \"Upload failed due to invalid file data. Please check your file and try again.\"\n : item.error.name === \"ZodError\"\n ? \"Upload failed due to a server error. Please try again later.\"\n : item.error.message}\n </div>\n )}\n </div>\n ))}\n\n {allComplete && (\n <div className=\"flex justify-between items-center\">\n <div className=\"text-body text-[var(--color-neutral-600)]\">\n {successfulCount} successful, {errorCount} failed\n </div>\n </div>\n )}\n </div>\n </BasePopup>\n );\n}\n","\"use client\";\n\nimport { AlertCircle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\n\ntype AuthErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n message: string;\n onClose: () => void;\n};\n\nexport default function AuthErrorPopup({ message, onClose, ...rest }: AuthErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Sign-in error\"\n isDismissable\n icon={AlertCircle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <p className=\"text-center text-lg font-medium text-[var(--color-text)]\">{message}</p>\n <Button onClick={onClose} variant=\"secondary\" className=\"w-full max-w-xs\">\n Close\n </Button>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { AlertTriangle, AlertCircle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { ErrorCode } from \"@behindthemusictree/app-kit/transport\";\n\ntype InternalErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n errorCode: ErrorCode;\n /**\n * Support contact email shown in the \"if the problem persists\" message. Passed by the\n * consuming app (from whatever env var / config it uses) so this package doesn't assume a\n * specific env var name.\n */\n contactEmail?: string | null;\n};\n\nexport default function InternalErrorPopup({ errorCode, contactEmail, ...rest }: InternalErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Internal Error\"\n isDismissable={false}\n icon={AlertTriangle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <AlertCircle className=\"h-16 w-16 text-[var(--color-red-500)]\" strokeWidth={1.5} />\n <div>\n <p className=\"text-center text-[var(--color-neutral-600)]\">\n Please try again. If the problem persists, contact us at{\" \"}\n <a href={`mailto:${contactEmail}`} className=\"text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]\">\n {contactEmail}\n </a>\n </p>\n </div>\n {errorCode && (\n <div className=\"text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]\">\n Error Code: {errorCode}\n </div>\n )}\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { AlertTriangle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { ErrorCode } from \"@behindthemusictree/app-kit/transport\";\n\ntype NetworkErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n errorCode: ErrorCode;\n};\n\nconst OFFLINE_MESSAGE = \"It seems that you are not connected to the internet. Please check your connection and try again.\";\nconst UNREACHABLE_MESSAGE = \"We couldn't reach the server. Please try again in a moment.\";\n\nexport default function NetworkErrorPopup({ errorCode, ...rest }: NetworkErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Network Error\"\n isDismissable={false}\n icon={AlertTriangle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <AlertTriangle className=\"h-16 w-16 text-[var(--color-neutral-600)]\" strokeWidth={1.5} />\n <p className=\"text-center text-[var(--color-neutral-700)]\">\n {errorCode === ErrorCode.NETWORK_OFFLINE ? OFFLINE_MESSAGE : UNREACHABLE_MESSAGE}\n </p>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\nimport { User } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { FaSpotify } from \"react-icons/fa\";\nimport { FcGoogle } from \"react-icons/fc\";\n\ntype AuthPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n handleSpotifyOAuth: (redirectAfterAuthPath?: string) => void;\n handleGoogleOAuth?: (redirectAfterAuthPath?: string) => void;\n redirectAfterAuthPath?: string;\n spotifyOnly?: boolean;\n message?: string;\n /**\n * Body copy shown when `spotifyOnly` is true. Wording (app name, feature description) is\n * app-specific, so each consuming app supplies its own instead of this package assuming one.\n */\n spotifyOnlyDescription: ReactNode;\n /** Body copy shown when `spotifyOnly` is false, for the same reason as `spotifyOnlyDescription`. */\n defaultDescription: ReactNode;\n};\n\nexport default function AuthPopup({\n handleSpotifyOAuth,\n handleGoogleOAuth,\n redirectAfterAuthPath,\n spotifyOnly,\n message,\n spotifyOnlyDescription,\n defaultDescription,\n ...rest\n}: AuthPopupProps) {\n const showGoogle = !spotifyOnly && handleGoogleOAuth;\n\n return (\n <BasePopup\n {...rest}\n title={spotifyOnly ? \"Connect with Spotify\" : \"Sign in\"}\n isDismissable={false}\n icon={User}\n type=\"auth\"\n children={\n <div className=\"flex flex-col items-center space-y-7\">\n <div className=\"px-2 text-center\">\n {message && <p className=\"mb-3 text-base font-medium leading-relaxed text-amber-200\">{message}</p>}\n <p className=\"text-lg font-medium leading-relaxed text-white\">\n {spotifyOnly ? spotifyOnlyDescription : defaultDescription}\n </p>\n </div>\n <div className=\"flex w-full flex-col items-center gap-3\">\n <Button\n onClick={() => handleSpotifyOAuth(redirectAfterAuthPath)}\n className=\"relative mb-2 w-fit transform bg-green-600 px-8 py-3 text-white shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-green-700 hover:shadow-xl\"\n >\n <span className=\"flex items-center justify-center\">\n <FaSpotify className=\"absolute left-6 text-3xl\" />\n <span className=\"w-full pl-14 pr-8 text-center text-lg font-medium\">Sign in with Spotify</span>\n </span>\n </Button>\n {showGoogle && (\n <Button\n variant=\"outline\"\n onClick={() => handleGoogleOAuth!(redirectAfterAuthPath)}\n className=\"relative w-fit transform border-white bg-white px-8 py-3 text-black shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-[var(--color-neutral-100)] hover:shadow-xl\"\n >\n <span className=\"flex items-center justify-center\">\n <FcGoogle className=\"absolute left-6 text-2xl\" />\n <span className=\"w-full pl-14 pr-8 text-center text-lg font-medium text-black\">\n Sign in with Google\n </span>\n </span>\n </Button>\n )}\n </div>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { FaSpotify } from \"react-icons/fa\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { User } from \"lucide-react\";\nimport { getSpotifyAllowlistMailtoHref } from \"@behindthemusictree/app-kit/transport\";\n\ntype SpotifyAuthErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n message: string;\n details?: string;\n onClose: () => void;\n /**\n * Support contact email used to build the allowlist-request mailto link. Passed by the\n * consuming app (from whatever env var / config it uses) so this package doesn't assume a\n * specific env var name.\n */\n contactEmail?: string | null;\n};\n\nexport default function SpotifyAuthErrorPopup({\n message,\n details,\n onClose,\n contactEmail = null,\n ...rest\n}: SpotifyAuthErrorPopupProps) {\n const requestAccessHref = getSpotifyAllowlistMailtoHref(contactEmail);\n\n return (\n <BasePopup\n {...rest}\n title=\"Authentication Failed\"\n isDismissable\n icon={User}\n children={\n <div className=\"flex flex-col items-center space-y-8 py-4\">\n <FaSpotify className=\"text-[#1DB954] text-7xl\" />\n <div className=\"space-y-3 text-center\">\n <p className=\"text-xl font-medium text-[var(--color-text)]\">{message}</p>\n {details && (\n <p className=\"text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]\">{details}</p>\n )}\n <div className=\"space-y-2 text-center\">\n <p className=\"text-base text-[var(--color-neutral-700)]\">\n The Spotify app is in development mode, so only allowlisted accounts can connect.\n </p>\n {requestAccessHref && contactEmail ? (\n <p className=\"text-base text-[var(--color-neutral-700)]\">\n Request access by emailing your{\" \"}\n <a\n href={requestAccessHref}\n className=\"text-[#1DB954] font-medium underline hover:no-underline focus:outline-none focus:ring-2 focus:ring-[#1DB954] focus:ring-offset-1 rounded\"\n >\n Spotify full name and Spotify email address\n </a>{\" \"}\n to{\" \"}\n <a\n href={requestAccessHref}\n className=\"text-[#1DB954] font-medium underline hover:no-underline focus:outline-none focus:ring-2 focus:ring-[#1DB954] focus:ring-offset-1 rounded\"\n >\n {contactEmail}\n </a>\n .\n </p>\n ) : (\n <p className=\"text-base text-[var(--color-neutral-700)]\">To request access, contact the app owner.</p>\n )}\n </div>\n </div>\n <Button\n onClick={onClose}\n className=\"bg-[#1DB954] hover:bg-[#1DB954]/90 text-white w-full max-w-xs transform transition-all duration-200 hover:scale-[1.02] shadow-lg hover:shadow-xl\"\n >\n <FaSpotify className=\"mr-2 text-lg\" />\n Try Again\n </Button>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\nimport { useAuthCallback, type AuthCallbackState, type UseAuthCallbackOptions } from \"@behindthemusictree/app-kit/auth\";\n\nexport interface AuthCallbackHandlerProps extends UseAuthCallbackOptions {\n /** Optional custom \"connecting…\" / error UI; defaults to a minimal full-screen overlay. */\n renderStatus?: (state: Exclude<AuthCallbackState, { status: null }>) => ReactNode;\n}\n\n/** Handles OAuth callbacks at layout level. Rendered in the app shell so it runs on every load. */\nexport default function AuthCallbackHandler({ renderStatus, ...options }: AuthCallbackHandlerProps) {\n const state = useAuthCallback(options);\n\n if (state.status === null) return null;\n\n if (renderStatus) return <>{renderStatus(state)}</>;\n\n if (state.status === \"error\") {\n return (\n <div className=\"fixed inset-0 z-[100] flex flex-col items-center justify-center bg-[var(--color-neutral-100)] p-4\">\n <div className=\"w-full max-w-md rounded-lg border border-[color-mix(in_srgb,var(--color-red-500)_20%,transparent)] bg-[color-mix(in_srgb,var(--color-red-500)_10%,transparent)] p-4\">\n <h2 className=\"mb-2 font-semibold text-[var(--color-red-500)]\">Authentication Error</h2>\n <p className=\"text-[color-mix(in_srgb,var(--color-red-500)_80%,transparent)]\">{state.message}</p>\n <button\n type=\"button\"\n onClick={state.goHome}\n className=\"mt-4 rounded bg-[var(--color-red-600)] px-4 py-2 text-white hover:bg-[var(--color-red-700)]\"\n >\n Go to home\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"fixed inset-0 z-[100] flex flex-col items-center justify-center bg-[var(--color-neutral-100)]\" data-page=\"auth-callback-handler\">\n <div className=\"text-center\">\n <h1 className=\"mb-4 text-2xl font-bold\">Connecting…</h1>\n <p className=\"text-[var(--color-neutral-600)]\">Completing sign-in.</p>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState, type ComponentProps, type ComponentType, type ReactNode } from \"react\";\nimport { useIsMutating } from \"@tanstack/react-query\";\nimport { z } from \"zod\";\nimport { Plus } from \"lucide-react\";\nimport { Maximize2, Minimize2 } from \"lucide-react\";\nimport { IconTextButton, IconButton, Button, SegmentedControl, DetailPanel, useObscuredInset } from \"@behindthemusictree/ui\";\n\nimport {\n GenreTreeWheelSkeleton,\n GenreTreeViewSkeleton,\n useGenreNodeRelations,\n} from \"@behindthemusictree/genre-tree-view\";\nimport type {\n GenreTreeAction,\n GenreTreeNode,\n GenreTreeViewMode,\n GenreTreeViewport,\n GenreTreeProps,\n GenreNodeStyleResolver,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport {\n CriteriaMinimum,\n CriteriaPlaylistSimple,\n toGenreUuid,\n type GenreUuid,\n type ArtistSearchResult,\n type RenderSongLink,\n type SongSearchResult,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaOverview } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useGenreTreeViewState, useArtist, useUpdateGenre, genreUpdateMutationKey } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport type { GenreDetailSlots } from \"./GenreDetailExtras\";\nimport type { GenrePlaylistTracksSlots } from \"./GenrePlaylistTracks\";\nimport type { HostOverlayPanel } from \"./overlayPanel\";\nimport { toTreeNodes } from \"./playlist-tree/toTreeNodes\";\nimport { toGenreNodeStyles } from \"./playlist-tree/toGenreNodeStyles\";\nimport type { RenderArtistLink, RenderPlaceLink } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport GenrePlaylistTreePerRoot from \"./playlist-tree/TreePerRoot\";\nimport GenrePlaylistTreeWheel from \"./playlist-tree/TreeWheel\";\nimport GenrePlaylistTreeWheelRadialPopCore, { type GenreFocusProps } from \"./playlist-tree/TreeWheelRadialPopCore\";\nimport { GenreTreeWheelHandoff } from \"./GenreTreeWheelHandoff\";\nimport { GenreTreeSearch, type GenreSearchGroupsProps } from \"./GenreTreeSearch\";\nimport { type SearchGroup } from \"./search\";\nimport { useGenreDetailContent } from \"./GenreDetailPanel\";\nimport ChangeParentPopup, { type ParentChange } from \"./ChangeParentPopup\";\nimport { useEntityPanel } from \"./useEntityPanel\";\nimport { SizeMetricToggle } from \"./SizeMetricToggle\";\nimport { hasViewsCount, type GenreTreeSizeMetric } from \"./playlist-tree/size-metric\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\nimport type { GetGenreTreeShareUrl, GenreTreeShareTarget } from \"./share\";\n\nexport type {\n FocusChangeReason,\n GenreTreeViewMode,\n} from \"@behindthemusictree/genre-tree-view\";\nexport type { GenreFocusProps } from \"./playlist-tree/TreeWheelRadialPopCore\";\n\n/** Artists are searched by default; picking one opens its panel (see `artistUuid`). */\nexport type ArtistSearchProps =\n | { artistSearch: false; onArtistSelect?: never; artistSearchBaseUrl?: never }\n | {\n artistSearch?: true;\n /** Notified when a suggestion is picked, after the view opens its artist panel. */\n onArtistSelect?: (artist: ArtistSearchResult) => void;\n /** Backend that serves `artists/` (search and the artist panel). Defaults to `getBackendBaseUrl`. */\n artistSearchBaseUrl?: () => string;\n };\n\nconst NO_POP_ROOT_TITLE = \"This genre tree has no 'Mainstream Pop' root yet\";\n\nexport type GenreTreeViewProps<O extends CriteriaOverview = CriteriaOverview> = {\n scope: Scope;\n /** \"regions\" lays the info panel out in the brand's left/center/right columns (see brand `--layout-center-*`). */\n placement?: \"default\" | \"regions\";\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n getBackendBaseUrl: () => string;\n /** Called after the Parent popup moved a genre; `from` and `to` are genre (criteria) uuids, `from` null for a root genre, `to` null when the genre was made a root. */\n onParentChanged?: (change: ParentChange) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n /** Controlled view mode. When provided, the internal Stacked/Wheel toggle is not rendered — the consumer owns that UI. */\n viewMode?: GenreTreeViewMode;\n /**\n * Selected genre entity, including genres outside the rendered tree. A raw URL value is accepted as is:\n * one that names no genre opens a \"not found\" panel.\n */\n selectedGenreUuid?: string | null;\n /** Called on every user-driven selection change (tree click, search pick, search clear). */\n onSelectedGenreUuidChange?: (genreUuid: GenreUuid | null) => void;\n /** Mount-only seed for the pan/zoom (wheel, pop-core and stacked views), replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Restore silently after layout; use a new revision for each navigation. Supply focus, selection,\n * and restoration together. User interaction supersedes a pending request. In stacked view,\n * the selected genre must resolve to a root; outline ignores restoration. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. In stacked view, only the tree holding the selection reports. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** When true, hides the \"Add root\" button and suppresses per-node\n * create/rename affordances, for a read-only consumer. Defaults to false. */\n readOnly?: boolean;\n /** Further result groups (e.g. places) shown in the search box next to genres, artists and songs. */\n extraSearchGroups?: SearchGroup[];\n /** Host search hooks run inside this subtree, so typing does not rerender the tree page. */\n SearchGroups?: ComponentType<GenreSearchGroupsProps>;\n /** Fires with the typed search text (empty when cleared), so a host can drive its own `extraSearchGroups`. */\n onSearchQueryChange?: (text: string) => void;\n /** Fires when the search box gains focus, e.g. to load data for `extraSearchGroups` lazily. */\n onSearchFocus?: () => void;\n /** Root element classes; the component adds no outer margin. */\n className?: string;\n /** Shows the \"Tree display options\" group (e.g. Rotation). Defaults to true. */\n showDisplayOptions?: boolean;\n /** Shows the \"Add root\" button (still hidden when `readOnly`). Defaults to true; a host rendering its own passes false. */\n showAddRoot?: boolean;\n /** Controlled wheel rotation. When provided, the internal Rotation toggle is not rendered — the consumer owns that UI. */\n allowWheelRotation?: boolean;\n /** Parses the selected genre's overview; pass an extended schema to keep consumer-specific fields. */\n criteriaOverviewSchema?: z.ZodType<O, unknown>;\n /** Consumer-specific rows rendered in the info panel after Summary. */\n renderGenreDetailExtras?: (overview: O) => ReactNode;\n /** Host control displayed before the size metric in the floating controls. */\n floatingControlsLeading?: ReactNode;\n /** Controlled size metric of the wheel and pop-core nodes: song count or summed song views. Uncontrolled when omitted\n * (starts on songs). The toggle is hidden while an artist filters the tree, which only has song counts. */\n sizeMetric?: GenreTreeSizeMetric;\n onSizeMetricChange?: (metric: GenreTreeSizeMetric) => void;\n /** When set, artist names in the info panel's track list render through it (e.g. a router `Link`). In the artist\n * panel, names otherwise render as buttons that switch the panel to that artist. */\n renderArtistLink?: RenderArtistLink;\n /** Controlled artist panel (an artist uuid). It shares the info panel's slot: opening an artist clears the selected\n * genre; selecting a genre keeps the artist as a filter (the tree shows only genres the artist has songs in, and\n * the genre's songs and play button are limited to the artist) and shows the genre's panel instead. A host\n * `overlayPanel` takes precedence over the artist panel. */\n artistUuid?: string | null;\n /** Called when the user opens an artist (search pick, member link) or closes its panel. */\n onArtistUuidChange?: (uuid: string | null) => void;\n /** Controlled expanded state of the artist panel. Uncontrolled, it resets to compact on each artist. */\n artistExpanded?: boolean;\n onArtistExpandedChange?: (expanded: boolean) => void;\n /** Controlled song panel (a song uuid). Like the artist panel it shares the info panel's slot: opening a song clears\n * the selected genre and the artist; selecting a genre closes it. A host `overlayPanel` takes precedence. */\n songUuid?: string | null;\n /** Called when the user opens a song (search pick, title link) or closes its panel. */\n onSongUuidChange?: (uuid: string | null) => void;\n /** Controlled expanded state of the song panel. Uncontrolled, it resets to compact on each song. */\n songExpanded?: boolean;\n onSongExpandedChange?: (expanded: boolean) => void;\n /** Songs are searched by default; picking one opens its panel. */\n songSearch?: boolean;\n onSongSelect?: (song: SongSearchResult) => void;\n /** When set, song titles in the info panel's track list render through it (e.g. a router `Link` to the song).\n * By default they are buttons that open the song panel. */\n renderSongLink?: RenderSongLink;\n /** When set, the artist panel renders the artist's origin through it (e.g. a router `Link` to the map region). */\n renderPlaceLink?: RenderPlaceLink;\n /** Resolves a selected genre, artist or song to a share URL using the host app's routes. */\n getShareUrl?: GetGenreTreeShareUrl;\n} & ArtistSearchProps &\n GenreDetailSlots<O> &\n GenrePlaylistTracksSlots &\n GenreFocusProps & {\n /** Appended to a selected genre's panel, e.g. destructive actions. */\n renderDangerZone?: (node: GenreTreeNode) => ReactNode;\n /** Controlled expanded state of the genre panel. Uncontrolled when omitted. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** A host panel rendered in the detail panel's slot; it takes precedence over the genre, song and artist panels.\n * Like theirs, its title fills the search field, whose clear button closes it. */\n overlayPanel?: HostOverlayPanel;\n /** Hides the info panel behind its edge tab; uncontrolled when omitted. Only applies with `placement=\"regions\"`. */\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n };\n\nconst REGIONS_CLASS =\n \"[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]\";\n\nconst noop = () => {};\n\nexport function GenreTreeView<O extends CriteriaOverview = CriteriaOverview>({\n scope,\n handleGenreCreationAction,\n handleGenreRenameAction,\n onParentChanged,\n getBackendBaseUrl,\n additionalActions,\n viewMode: controlledViewMode,\n selectedGenreUuid: controlledSelectedGenreUuid,\n onSelectedGenreUuidChange,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n readOnly = false,\n className,\n showDisplayOptions = true,\n showAddRoot = true,\n allowWheelRotation: controlledAllowWheelRotation,\n criteriaOverviewSchema,\n renderGenreDetailExtras,\n floatingControlsLeading,\n sizeMetric: controlledSizeMetric,\n onSizeMetricChange,\n renderArtistLink,\n artistUuid: controlledArtistUuid,\n onArtistUuidChange,\n artistExpanded: controlledArtistExpanded,\n onArtistExpandedChange,\n getShareUrl,\n extraSearchGroups = [],\n SearchGroups,\n onSearchQueryChange,\n onSearchFocus,\n artistSearch = true,\n onArtistSelect,\n artistSearchBaseUrl,\n songUuid: controlledSongUuid,\n onSongUuidChange,\n songExpanded: controlledSongExpanded,\n onSongExpandedChange,\n songSearch = true,\n onSongSelect,\n renderSongLink,\n renderPlaceLink,\n renderSummary,\n renderEssentialTracks,\n renderSongLeading,\n renderSongActions,\n renderTracksToolbar,\n renderDangerZone,\n expanded,\n onExpandedChange,\n collapsed,\n onCollapsedChange,\n overlayPanel,\n placement = \"default\",\n ...focus\n}: GenreTreeViewProps<O>) {\n const getShareUrlRef = useRef(getShareUrl);\n getShareUrlRef.current = getShareUrl;\n const [internalArtistUuid, setInternalArtistUuid] = useState<string | null>(null);\n const isArtistControlled = controlledArtistUuid !== undefined;\n const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;\n const [internalSongUuid, setInternalSongUuid] = useState<string | null>(null);\n const isSongControlled = controlledSongUuid !== undefined;\n const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;\n const changeSong = (uuid: string | null) => {\n if (!isSongControlled) setInternalSongUuid(uuid);\n onSongUuidChange?.(uuid);\n };\n const [internalSizeMetric, setInternalSizeMetric] = useState<GenreTreeSizeMetric>(\"songs\");\n const sizeMetric = controlledSizeMetric ?? internalSizeMetric;\n const deferredSizeMetric = useDeferredValue(sizeMetric);\n const changeSizeMetric = (metric: GenreTreeSizeMetric) => {\n if (controlledSizeMetric === undefined) setInternalSizeMetric(metric);\n onSizeMetricChange?.(metric);\n };\n const changeArtist = (uuid: string | null) => {\n if (!isArtistControlled) setInternalArtistUuid(uuid);\n onArtistUuidChange?.(uuid);\n };\n const {\n isLoading,\n isError,\n refetch,\n isFetching: isTreeFetching,\n genrePlaylistByNodeId,\n visibleGenrePlaylists,\n focusUuids,\n groupedGenrePlaylistsByRoot,\n selectedGenreUuid,\n selectGenre,\n selectedNodeId,\n selectedGenrePlaylist,\n selectNode,\n selectGenrePlaylist,\n clearSelection,\n viewMode,\n isViewModeControlled: isControlled,\n setViewMode,\n canShowPopCore,\n allowWheelRotation: internalAllowWheelRotation,\n toggleWheelRotation,\n onNodeHover: handleNodeHover,\n } = useGenreTreeViewState<O>({\n scope,\n getBackendBaseUrl,\n viewMode: controlledViewMode,\n selectedGenreUuid: controlledSelectedGenreUuid,\n onSelectedGenreUuidChange,\n criteriaOverviewSchema,\n artistUuid,\n });\n\n // Renderer revision tracking is per instance: bind a navigation to one stacked root so a\n // later user selection cannot replay the same request in another renderer.\n const restoreRevision = viewportRestore?.revision;\n const [stackedRestoreOwner, setStackedRestoreOwner] = useState<{\n revision: string | number | undefined;\n rootUuid: string | undefined;\n }>({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });\n let restoreRootUuid = stackedRestoreOwner.rootUuid;\n if (stackedRestoreOwner.revision !== restoreRevision) {\n restoreRootUuid = selectedGenrePlaylist?.root.uuid;\n setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });\n } else if (restoreRootUuid === undefined && selectedGenrePlaylist) {\n restoreRootUuid = selectedGenrePlaylist.root.uuid;\n setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });\n }\n\n const isGenreUpdating = useIsMutating({ mutationKey: genreUpdateMutationKey }) > 0;\n const { mutate: updateGenre } = useUpdateGenre(scope, getBackendBaseUrl);\n const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;\n // The artist detail can load after the filtered counts, so use the UUID as the filter state.\n const isArtistFiltered = artistUuid !== null;\n const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);\n\n const artistResult = useArtist(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);\n const filterArtistName = artistResult.status === \"success\" ? artistResult.artist.name : null;\n const filterArtist = useMemo(\n () => (artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null),\n [artistUuid, filterArtistName],\n );\n const hasSelectedGenreNode =\n selectedGenrePlaylist !== undefined && visibleGenrePlaylists.some(({ uuid }) => uuid === selectedGenrePlaylist.uuid);\n const playback = useGenrePlaylistPlayback({ scope, genrePlaylists: visibleGenrePlaylists, artist: filterArtist });\n const openArtist = (uuid: string) => {\n if (selectedGenreUuid !== null) clearSelection();\n if (songUuid !== null) changeSong(null);\n changeArtist(uuid);\n };\n const openSong = (uuid: string) => {\n if (selectedGenreUuid !== null) clearSelection();\n changeSong(uuid);\n };\n // Kept stable: it feeds the memoized info panel body, which must not rebuild on every render.\n const openSongRef = useRef(openSong);\n openSongRef.current = openSong;\n const resolvedRenderSongLink = useCallback<RenderSongLink>(\n (song) =>\n renderSongLink ? (\n renderSongLink(song)\n ) : (\n <button type=\"button\" onClick={() => openSongRef.current(song.uuid)} className=\"hover:underline\">\n {song.title}\n </button>\n ),\n [renderSongLink],\n );\n const [expandedSongUuid, setExpandedSongUuid] = useState<string | null>(null);\n // Keyed by artist, so switching artists (including a host's back/forward) starts compact.\n const [expandedArtistUuid, setExpandedArtistUuid] = useState<string | null>(null);\n const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;\n const songBaseUrl = getBackendBaseUrl;\n const resolvedRenderArtistLink: RenderArtistLink =\n renderArtistLink ??\n ((artist) =>\n artist.isSpecialPurpose ? (\n artist.name\n ) : (\n <button type=\"button\" onClick={() => openArtist(artist.uuid)} className=\"hover:underline\">\n {artist.name}\n </button>\n ));\n const getGenrePath = (genre: CriteriaMinimum): CriteriaPlaylistSimple[] => {\n const path: CriteriaPlaylistSimple[] = [];\n let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);\n while (current) {\n path.unshift(current);\n const parentUuid: string | undefined = current.parent?.uuid;\n current = parentUuid ? visibleGenrePlaylists.find((playlist) => playlist.uuid === parentUuid) : undefined;\n }\n return path;\n };\n const entityPanel = useEntityPanel({\n scope,\n getBackendBaseUrl: songBaseUrl,\n getArtistBackendBaseUrl: artistBaseUrl,\n getShareUrl: getShareUrlRef.current,\n renderArtistLink: resolvedRenderArtistLink,\n renderSongLink: resolvedRenderSongLink,\n renderPlaceLink,\n song: {\n uuid: songUuid,\n expanded: controlledSongExpanded ?? (songUuid !== null && expandedSongUuid === songUuid),\n onExpandedChange: (on) => {\n if (controlledSongExpanded === undefined) setExpandedSongUuid(on ? songUuid : null);\n onSongExpandedChange?.(on);\n },\n onClose: () => changeSong(null),\n },\n artist: {\n uuid: artistUuid,\n expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),\n onExpandedChange: (on) => {\n if (controlledArtistExpanded === undefined) setExpandedArtistUuid(on ? artistUuid : null);\n onArtistExpandedChange?.(on);\n },\n onClose: () => changeArtist(null),\n },\n getGenrePath,\n onSelectGenrePlaylist: (genrePlaylist) => {\n changeSong(null);\n selectGenrePlaylist(genrePlaylist);\n },\n });\n // A host panel takes precedence over the genre's; a selected genre's panel replaces the artist's or song's, and the\n // artist stays active as a filter.\n const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? undefined : entityPanel);\n\n const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(false);\n const [uncontrolledExpanded, setUncontrolledExpanded] = useState(false);\n const isCollapsed = collapsed ?? uncontrolledCollapsed;\n const isExpanded = expanded ?? uncontrolledExpanded;\n const changeCollapsed = (next: boolean) => {\n setUncontrolledCollapsed(next);\n onCollapsedChange?.(next);\n };\n const changeExpanded = (next: boolean) => {\n setUncontrolledExpanded(next);\n onExpandedChange?.(next);\n };\n useEffect(() => {\n setUncontrolledCollapsed(false);\n }, [selectedGenreUuid, artistUuid, songUuid]);\n\n const [isWheelRevealed, setIsWheelRevealed] = useState(false);\n const usesHandoff = viewMode === \"wheel\" || viewMode === \"pop-core\";\n // The panel stands beside a tree that fades in, so it waits for the tree.\n const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);\n\n // The tree publishes how it draws each node; the panel header and family chips reuse it.\n const [resolveStyle, setResolveStyle] = useState<GenreNodeStyleResolver | null>(null);\n const handleNodeStyleResolverChange = useCallback(\n (resolver: GenreNodeStyleResolver) => setResolveStyle(() => resolver),\n [],\n );\n const panelRef = useRef<HTMLDivElement>(null);\n const obscuredInset = useObscuredInset(panelRef);\n const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };\n\n const nodeMetric: GenreTreeSizeMetric = isArtistFiltered || !canSizeByViews ? \"songs\" : deferredSizeMetric;\n const treeNodes = useMemo(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);\n const relations = useGenreNodeRelations(\n treeNodes,\n !overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,\n resolveStyle,\n );\n\n const treeStyles = useMemo(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);\n\n const validSelectedGenreUuid = toGenreUuid(selectedGenreUuid);\n const [selectionHistory, setSelectionHistory] = useState<{ current: GenreUuid | null; previous: GenreUuid | null }>({ current: validSelectedGenreUuid, previous: null });\n if (selectionHistory.current !== validSelectedGenreUuid) {\n setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });\n }\n const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : undefined;\n\n const { showPopup, hidePopup } = usePopup();\n const reopenPanel = () => { setUncontrolledCollapsed(false); onCollapsedChange?.(false); };\n const handleSelectedNodeChange = (node: { id: string } | null) => {\n reopenPanel();\n if (node !== null && songUuid !== null) changeSong(null);\n selectNode(node);\n };\n const handleGenreSearchSelect = (genrePlaylist: CriteriaPlaylistSimple) => {\n reopenPanel();\n if (songUuid !== null) changeSong(null);\n selectGenrePlaylist(genrePlaylist);\n };\n\n // Mirrors genre-tree-view's isZoomableNode: a node zooms when it has children and at most one pop-side child.\n const selectedUuid = selectedGenrePlaylist?.uuid;\n const selectedChildren = selectedUuid\n ? visibleGenrePlaylists.filter((genrePlaylist) => genrePlaylist.parent?.uuid === selectedUuid)\n : [];\n const canZoomIn =\n viewMode === \"pop-core\" &&\n focus.onFocusGenreChange !== undefined &&\n selectedUuid !== undefined &&\n focus.focusGenreUuid !== selectedUuid &&\n selectedChildren.length > 0 &&\n selectedChildren.filter((child) => child.criteria?.side === \"pop\").length <= 1;\n const handleGenreSearchZoomIn = () => {\n if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, \"zoom-in\");\n };\n const zoomInRef = useRef<(() => void) | undefined>(undefined);\n zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : undefined;\n\n const genrePlaylist = selectedGenrePlaylist;\n const criteria = genrePlaylist?.criteria;\n const parentPlaylist = visibleGenrePlaylists.find(({ uuid }) => uuid === genrePlaylist?.parent?.uuid);\n const canToggleSide = !readOnly && criteria !== undefined && criteria !== null && parentPlaylist !== undefined && parentPlaylist.parent === null;\n const side = criteria?.side ?? \"core\";\n const popSibling = canToggleSide && side === \"core\" ? visibleGenrePlaylists.find((sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist?.uuid && sibling.criteria?.side === \"pop\") : undefined;\n const shareTarget: GenreTreeShareTarget | undefined = validSelectedGenreUuid ? { kind: \"genre\", genreUuid: validSelectedGenreUuid, name: criteria?.name ?? \"Genre\", scope, artistUuid } : undefined;\n const shareUrl = shareTarget ? getShareUrlRef.current?.(shareTarget) ?? undefined : undefined;\n const genreContent = useGenreDetailContent<O>({\n genreUuid: selectedGenreUuid,\n scope, getBackendBaseUrl,\n onSelectGenre: (uuid) => { reopenPanel(); selectGenre(uuid); },\n expanded: isExpanded,\n treeStyles,\n playback,\n genrePlaylist: selectedGenrePlaylist,\n band: {\n ...(relations ? { node: relations.node } : {}),\n shareTarget: shareUrl ? shareTarget : undefined, shareUrl,\n onZoomIn: zoomInRef.current,\n onAddChild: readOnly || !criteria ? undefined : () => handleGenreCreationAction(criteria),\n onRename: readOnly || !criteria ? undefined : () => handleGenreRenameAction(criteria),\n onChangeParent: readOnly || !genrePlaylist || !criteria\n ? undefined\n : () =>\n showPopup(\n <ChangeParentPopup\n genrePlaylist={{ ...genrePlaylist, criteria }}\n genrePlaylists={visibleGenrePlaylists}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n onClose={hidePopup}\n onParentChanged={onParentChanged}\n />,\n ),\n side,\n onToggleSide: canToggleSide && criteria\n ? () => updateGenre({ uuid: criteria.uuid, data: { side: side === \"pop\" ? \"core\" : \"pop\" } })\n : undefined,\n toggleSideDisabledReason: popSibling\n ? `${popSibling.name} is already the pop side of ${parentPlaylist?.name}`\n : undefined,\n additionalActions,\n },\n extras: { criteriaOverviewSchema, renderGenreDetailExtras, renderArtistLink,\n renderSongLink: resolvedRenderSongLink, artist: filterArtist, renderSummary,\n renderEssentialTracks, renderSongLeading, renderSongActions, renderTracksToolbar },\n trailing: relations ? renderDangerZone?.(relations.node) : undefined,\n });\n\n const isRotationControlled = controlledAllowWheelRotation !== undefined;\n const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;\n\n type ActivePanel = {\n title: ReactNode;\n content: ReactNode;\n aside?: ReactNode;\n expanded: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n onClose: () => void;\n // Every panel's name lives in the search field, and the search field closes it; null leaves the field empty.\n searchName: string | null;\n headerAccent?: { background: string; color: string };\n };\n let activePanel: ActivePanel | null = null;\n if (otherPanel) {\n activePanel = {\n title: otherPanel.title,\n content: otherPanel.content,\n aside: otherPanel.extraContent,\n expanded: otherPanel.expanded ?? false,\n onExpandedChange: otherPanel.onExpandedChange,\n onClose: otherPanel.onClose,\n searchName: otherPanel.title,\n };\n } else if (selectedGenreUuid !== null) {\n activePanel = {\n title: genreContent.title,\n content: genreContent.content,\n aside: genreContent.aside,\n expanded: isExpanded,\n onExpandedChange: changeExpanded,\n onClose: clearSelection,\n searchName: genreContent.name,\n headerAccent: genreContent.headerAccent,\n };\n }\n const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);\n\n const detailTab =\n placement === \"regions\" && activePanel?.onExpandedChange\n ? {\n edge: activePanel.expanded\n ? { label: \"Shrink panel\", onClick: () => activePanel.onExpandedChange?.(false) }\n : isCollapsed\n ? null\n : { label: \"Hide panel\", onClick: () => changeCollapsed(true) },\n center: activePanel.expanded\n ? null\n : isCollapsed\n ? { label: \"Show panel\", onClick: () => changeCollapsed(false) }\n : activePanel.onExpandedChange\n ? { label: \"Extend panel\", onClick: () => activePanel.onExpandedChange?.(true) }\n : null,\n }\n : undefined;\n\n const expandButton =\n placement === \"default\" && activePanel?.onExpandedChange ? (\n <IconButton\n aria-label={activePanel.expanded ? \"Shrink panel\" : \"Extend panel\"}\n style={activePanel.headerAccent && { color: \"inherit\" }}\n onClick={() => activePanel.onExpandedChange?.(!activePanel.expanded)}\n >\n {activePanel.expanded ? (\n <Minimize2 aria-hidden=\"true\" className=\"h-4 w-4\" />\n ) : (\n <Maximize2 aria-hidden=\"true\" className=\"h-4 w-4\" />\n )}\n </IconButton>\n ) : null;\n\n const renderArtistFilter = () => {\n if (isLoading || !filterArtist) return null;\n return (\n <span className=\"inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body\">\n <button\n type=\"button\"\n className=\"py-1 pl-3 pr-2 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] hover:underline\"\n aria-label={`Show artist ${filterArtist.name}`}\n onClick={() => {\n if (selectedGenreUuid !== null) clearSelection();\n }}\n >\n {filterArtist.name}\n </button>\n <button\n type=\"button\"\n className=\"py-1 pl-1 pr-3 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] hover:text-[var(--color-text)]\"\n aria-label={`Clear artist filter ${filterArtist.name}`}\n onClick={() => changeArtist(null)}\n >\n ×\n </button>\n </span>\n );\n };\n\n const actions = (\n <>\n {!isLoading && !isError && (\n <GenreTreeSearch\n artistBaseUrl={artistBaseUrl}\n songBaseUrl={songBaseUrl}\n artistSearch={Boolean(artistSearch)}\n songSearch={Boolean(songSearch)}\n onArtistSelect={(artist) => { openArtist(artist.uuid); onArtistSelect?.(artist); }}\n onSongSelect={(song) => { openSong(song.uuid); onSongSelect?.(song); }}\n SearchGroups={SearchGroups}\n genrePlaylists={visibleGenrePlaylists}\n onSelect={handleGenreSearchSelect}\n onSelectGenre={(uuid) => { reopenPanel(); if (songUuid) changeSong(null); selectGenre(uuid); }}\n selectedName={activePanel?.searchName ?? null}\n onClear={activePanel?.onClose}\n showClear={activePanel !== null}\n clearLabel=\"Close panel\"\n onPrevious={handlePrevious}\n onQueryChange={onSearchQueryChange}\n onFocus={onSearchFocus}\n extraGroups={extraSearchGroups}\n />\n )}\n {!isLoading && !isError && filterArtist && (\n <div className=\"hidden w-full justify-center max-md:flex\">{renderArtistFilter()}</div>\n )}\n <div className=\"contents max-md:flex max-md:w-full max-md:items-center max-md:gap-2 max-md:overflow-x-auto max-md:[scrollbar-width:none] max-md:[&>*]:shrink-0\">\n {!isLoading && !isError && !isControlled && (\n <SegmentedControl\n aria-label=\"Tree view mode\"\n value={viewMode}\n onChange={setViewMode}\n options={[\n { value: \"pop-core\", label: \"Pop/Core\", disabled: !canShowPopCore, title: canShowPopCore ? undefined : NO_POP_ROOT_TITLE },\n { value: \"wheel\", label: \"Wheel\" },\n { value: \"stacked\", label: \"Stacked\" },\n { value: \"outline\", label: \"Outline\", disabled: !canShowPopCore, title: canShowPopCore ? undefined : NO_POP_ROOT_TITLE },\n ]}\n />\n )}\n {!isLoading && !isError && showDisplayOptions && (\n <div\n className=\"flex items-center gap-1\"\n role=\"group\"\n aria-label=\"Tree display options\"\n >\n {!isRotationControlled && viewMode !== \"stacked\" && viewMode !== \"outline\" && (\n <Button\n variant={allowWheelRotation ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={toggleWheelRotation}\n >\n Rotation\n </Button>\n )}\n </div>\n )}\n {!isLoading && !isError && !readOnly && showAddRoot && (\n <IconTextButton\n icon={Plus}\n text=\"Add root\"\n onClick={() => handleGenreCreationAction(null)}\n />\n )}\n </div>\n </>\n );\n\n return (\n <div\n data-left-panel={isPanelShown && !isCollapsed ? undefined : \"hidden\"}\n className={[\"genre-tree-view relative flex flex-col h-full\", placement === \"regions\" && REGIONS_CLASS, className]\n .filter(Boolean)\n .join(\" \")}\n >\n <div\n className={`actions-container absolute z-30 flex items-center gap-2 ${\n placement === \"regions\"\n ? \"left-[calc(var(--layout-gutter)+var(--layout-panel-inset))] top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:left-[var(--layout-panel-inset)] md:top-[var(--layout-panel-inset)] max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:top-[var(--layout-band-top)] max-md:flex-col max-md:items-stretch\"\n : \"left-5 top-5\"\n }`}\n >\n {actions}\n </div>\n {!isLoading && !isError && filterArtist && (\n <div\n className={`absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${\n placement === \"regions\" ? \"top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:top-[var(--layout-panel-inset)]\" : \"top-5\"\n }`}\n >\n {renderArtistFilter()}\n </div>\n )}\n <div className=\"content-container flex-1 min-h-0 flex flex-row gap-4\">\n <div className=\"tree-view-container relative flex-1 min-w-0 flex flex-col h-full\">\n {!isLoading && !isError && viewMode === \"outline\" && floatingControlsLeading && (\n <div className=\"absolute bottom-3 right-3 z-10\">{floatingControlsLeading}</div>\n )}\n {isLoading ? (\n <GenreTreeViewSkeleton viewMode={viewMode} />\n ) : isError ? (\n <p role=\"alert\" className=\"m-auto text-center\">\n Couldn&apos;t load the genre tree.{\" \"}\n <button type=\"button\" className=\"underline\" onClick={refetch}>\n Retry\n </button>\n </p>\n ) : viewMode === \"wheel\" ? (\n // The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,\n // and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,\n // Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.\n // The panel's own Zoom in button is hidden: the search bar carries it.\n <div className=\"tree-container search-overlay relative flex-1 w-full min-h-0 \">\n <GenreTreeWheelHandoff skeleton={<GenreTreeWheelSkeleton />} onRevealedChange={setIsWheelRevealed}>\n <GenrePlaylistTreeWheel\n scope={scope}\n genrePlaylists={visibleGenrePlaylists}\n focusUuids={focusUuids}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n selectedNodeId={selectedNodeId}\n readOnly={readOnly}\n allowWheelRotation={allowWheelRotation}\n sizeMetric={isArtistFiltered || !canSizeByViews ? \"songs\" : deferredSizeMetric}\n busy={busy}\n floatingControlsLeading={\n floatingControlsLeading || canSizeByViews ? (\n <div className=\"flex items-center gap-2\">\n {floatingControlsLeading}\n {canSizeByViews && <SizeMetricToggle value={sizeMetric} onChange={changeSizeMetric} />}\n </div>\n ) : undefined\n }\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n />\n </GenreTreeWheelHandoff>\n </div>\n ) : viewMode === \"pop-core\" ? (\n // Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.\n <div className=\"tree-container search-overlay relative flex-1 w-full min-h-0 \">\n <GenreTreeWheelHandoff skeleton={<GenreTreeWheelSkeleton />} onRevealedChange={setIsWheelRevealed}>\n <GenrePlaylistTreeWheelRadialPopCore\n scope={scope}\n genrePlaylists={visibleGenrePlaylists}\n focusUuids={focusUuids}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n selectedNodeId={selectedNodeId}\n readOnly={readOnly}\n allowWheelRotation={allowWheelRotation}\n sizeMetric={isArtistFiltered || !canSizeByViews ? \"songs\" : deferredSizeMetric}\n busy={busy}\n floatingControlsLeading={\n floatingControlsLeading || canSizeByViews ? (\n <div className=\"flex items-center gap-2\">\n {floatingControlsLeading}\n {canSizeByViews && <SizeMetricToggle value={sizeMetric} onChange={changeSizeMetric} />}\n </div>\n ) : undefined\n }\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...focus}\n />\n </GenreTreeWheelHandoff>\n </div>\n ) : viewMode === \"outline\" ? (\n <div className=\"tree-container flex-1 min-h-0 w-full overflow-y-auto relative\">\n <GenrePlaylistTreeWheelRadialPopCore\n outline\n scope={scope}\n genrePlaylists={visibleGenrePlaylists}\n focusUuids={focusUuids}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n selectedNodeId={selectedNodeId}\n readOnly={readOnly}\n />\n </div>\n ) : (\n <div className=\"tree-container relative flex flex-col gap-4 w-full pt-14 overflow-x-auto overflow-y-auto text-[var(--color-text)]\">\n {Object.entries(groupedGenrePlaylistsByRoot).map(\n ([uuid, genrePlaylistTreePerRoot]) => {\n return (\n <div\n key={uuid}\n className=\"tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg\"\n >\n <div className=\"graph-container relative z-10 h-full\">\n <GenrePlaylistTreePerRoot\n scope={scope}\n rootUuid={uuid}\n genrePlaylistTreePerRoot={genrePlaylistTreePerRoot}\n handleGenreCreationAction={handleGenreCreationAction}\n handleGenreRenameAction={handleGenreRenameAction}\n additionalActions={additionalActions}\n onSelectedNodeChange={handleSelectedNodeChange}\n onNodeHover={handleNodeHover}\n {...hostPanel}\n playback={playback}\n focusUuids={focusUuids}\n // Each root has its own panel; null closes the one not holding the selection.\n selectedNodeId={\n uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null\n }\n readOnly={readOnly}\n wheelZoom=\"modifier\"\n defaultViewport={\n uuid === selectedGenrePlaylist?.root.uuid ? defaultViewport : undefined\n }\n viewportRestore={\n uuid === selectedGenrePlaylist?.root.uuid && uuid === restoreRootUuid ? viewportRestore : undefined\n }\n onViewportChange={\n uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : undefined\n }\n />\n </div>\n </div>\n );\n },\n )}\n </div>\n )}\n {/* Always mounted: useObscuredInset observes the node once, so it must exist when the host mounts. */}\n <DetailPanel\n ref={panelRef}\n side=\"left\"\n title={activePanel?.title ?? \"\"}\n titleInSearch={!isLoading && !isError}\n headerAccent={activePanel?.headerAccent}\n headerActions={expandButton}\n onClose={activePanel?.onClose ?? noop}\n collapsed={isCollapsed || !isPanelShown}\n expanded={activePanel?.expanded}\n onExpandedChange={activePanel?.onExpandedChange}\n aside={activePanel?.aside}\n edgeTab={detailTab}\n >\n {activePanel?.aside && !activePanel.expanded ? (\n <>\n {activePanel.content}\n {activePanel.aside}\n </>\n ) : (\n activePanel?.content\n )}\n </DetailPanel>\n </div>\n </div>\n </div>\n );\n}\n","import { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport type GenreTreeSizeMetric = \"songs\" | \"views\";\n\nexport const hasViewsCount = (genrePlaylists: CriteriaPlaylistSimple[]): boolean =>\n genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== undefined);\n\nexport const genrePlaylistSize = (genrePlaylist: CriteriaPlaylistSimple, metric: GenreTreeSizeMetric): number => {\n if (metric === \"songs\") return genrePlaylistTrackCount(genrePlaylist);\n if (genrePlaylist.viewsCount === undefined) {\n throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);\n }\n return genrePlaylist.viewsCount;\n};\n","import type { GenreTreeNode } from \"@behindthemusictree/genre-tree-view\";\nimport type { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { genrePlaylistSize, type GenreTreeSizeMetric } from \"./size-metric\";\n\n/** The tree nodes of a set of genre playlists, as every tree renderer and the host's detail panel see them. */\nexport function toTreeNodes(\n genrePlaylists: CriteriaPlaylistSimple[],\n sizeMetric: GenreTreeSizeMetric,\n /** The open artist's footprint: every node outside it is muted. Omit it to mute nothing. */\n focusUuids?: ReadonlySet<string>,\n): GenreTreeNode[] {\n return genrePlaylists.map((genrePlaylist) => ({\n id: genrePlaylist.uuid,\n parentId: genrePlaylist.parent?.uuid ?? null,\n name: genrePlaylist.name,\n itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),\n actionable: Boolean(genrePlaylist.criteria),\n detached: !genrePlaylist.criteria,\n side: genrePlaylist.criteria?.side ?? undefined,\n wikidataId: genrePlaylist.criteria?.wikidataId ?? null,\n umbrella: genrePlaylist.isUmbrella,\n scene: genrePlaylist.scene ?? undefined,\n muted: focusUuids ? !focusUuids.has(genrePlaylist.uuid) : undefined,\n }));\n}\n","import type { GenreNodeRelations, GenreNodeStyle } from \"@behindthemusictree/genre-tree-view\";\nimport type { CriteriaPlaylistSimple, GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\n\n/**\n * How the tree draws the selected genre and its relatives, keyed by genre uuid.\n * Tree nodes are keyed by genre playlist uuid, a different id space, so the detail panel cannot look them up directly.\n */\nexport function toGenreNodeStyles(\n relations: GenreNodeRelations | null,\n genrePlaylists: CriteriaPlaylistSimple[],\n): ReadonlyMap<GenreUuid, GenreNodeStyle> {\n const styles = new Map<GenreUuid, GenreNodeStyle>();\n if (!relations) return styles;\n const genreUuidByPlaylistUuid = new Map<string, GenreUuid>(\n genrePlaylists.flatMap((genrePlaylist) => (genrePlaylist.criteria ? [[genrePlaylist.uuid, genrePlaylist.criteria.uuid] as const] : [])),\n );\n const drawn = [relations, relations.parentNode, ...relations.childNodes, ...relations.ancestorNodes];\n for (const entry of drawn) {\n const genreUuid = entry && genreUuidByPlaylistUuid.get(entry.node.id);\n if (entry && genreUuid) styles.set(genreUuid, { fill: entry.fill, textColor: entry.textColor });\n }\n return styles;\n}\n","\"use client\";\n\nimport { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { useCallback, useMemo } from \"react\";\nimport {\n GenreTree,\n getGenreTreeColor,\n type GenreTreeViewport,\n type GenreTreeProps,\n type GenreTreeAction,\n type GenreTreeNode,\n type WheelZoomMode,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaMinimum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { HostPanelProps } from \"./hostPanelProps\";\nimport { toTreeNodes } from \"./toTreeNodes\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./useGenrePlaylistPlayback\";\n\nexport type GenrePlaylistTreePerRootProps<T extends TrackBase> = {\n scope: Scope;\n className?: string;\n rootUuid: string;\n genrePlaylistTreePerRoot: CriteriaPlaylistSimple[];\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n onNodeClick?: (node: GenreTreeNode) => void;\n onNodeHover?: (node: GenreTreeNode) => void;\n /** Overrides which node is shown highlighted, e.g. from a search selection. */\n selectedNodeId?: string | null;\n /** Fires when a user action changes the info panel's node, or `null` when it is closed. */\n onSelectedNodeChange?: (node: GenreTreeNode | null) => void;\n /** When true, suppresses per-node create/rename affordances. Defaults to false. */\n readOnly?: boolean;\n wheelZoom?: WheelZoomMode;\n /** Mount-only seed for the pan/zoom, replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Runtime viewport restoration request. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** What node play buttons play; defaults to each node's whole genre playlist. */\n playback?: GenrePlaylistPlayback;\n /** The open artist's footprint; nodes outside it are drawn muted. */\n focusUuids?: ReadonlySet<string>;\n} & HostPanelProps;\n\nexport default function GenrePlaylistTreePerRoot<T extends TrackBase>({\n scope,\n className,\n rootUuid,\n genrePlaylistTreePerRoot,\n handleGenreCreationAction,\n handleGenreRenameAction,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n readOnly = false,\n wheelZoom,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n playback,\n focusUuids,\n ...hostPanel\n}: GenrePlaylistTreePerRootProps<T>) {\n const { isPlaying, setIsPlaying } = usePlayer();\n const defaultPlayback = useGenrePlaylistPlayback<T>({ scope, genrePlaylists: genrePlaylistTreePerRoot });\n const { playing, play } = playback ?? defaultPlayback;\n const playingNodeId = playing?.uuid ?? null;\n\n const nodes = useMemo(\n () => toTreeNodes(genrePlaylistTreePerRoot, \"songs\", focusUuids),\n [genrePlaylistTreePerRoot, focusUuids],\n );\n\n const handlePlayPause = useCallback(\n (nodeId: string) => {\n const genrePlaylist = genrePlaylistTreePerRoot.find((g) => g.uuid === nodeId);\n if (!genrePlaylist) return;\n\n if (nodeId === playingNodeId) {\n setIsPlaying(!isPlaying);\n return;\n }\n\n if (genrePlaylistTrackCount(genrePlaylist) === 0) {\n return;\n }\n\n void play(genrePlaylist);\n },\n [\n genrePlaylistTreePerRoot,\n playingNodeId,\n isPlaying,\n setIsPlaying,\n play,\n ],\n );\n\n const handleAddChild = useCallback(\n (parentId: string) => {\n const genrePlaylist = genrePlaylistTreePerRoot.find((g) => g.uuid === parentId);\n if (!genrePlaylist?.criteria) return;\n handleGenreCreationAction(genrePlaylist.criteria);\n },\n [genrePlaylistTreePerRoot, handleGenreCreationAction],\n );\n\n const handleRenameRequest = useCallback(\n (node: GenreTreeNode) => {\n const genrePlaylist = genrePlaylistTreePerRoot.find((g) => g.uuid === node.id);\n if (!genrePlaylist?.criteria) return;\n handleGenreRenameAction(genrePlaylist.criteria);\n },\n [genrePlaylistTreePerRoot, handleGenreRenameAction],\n );\n\n const handleDeleteRequest = useCallback((node: GenreTreeNode) => {\n if (confirm(`Are you sure you want to delete \"${node.name}\"?`)) {\n // TODO: Implement delete genre\n }\n }, []);\n\n return (\n <GenreTree\n className={className}\n nodes={nodes}\n rootColor={getGenreTreeColor(rootUuid)}\n playingNodeId={playingNodeId}\n playState={isPlaying ? \"playing\" : \"paused\"}\n onPlayPause={handlePlayPause}\n onAddChild={readOnly ? undefined : handleAddChild}\n onRenameRequest={readOnly ? undefined : handleRenameRequest}\n onDeleteRequest={readOnly ? undefined : handleDeleteRequest}\n additionalActions={additionalActions}\n onNodeClick={onNodeClick}\n onNodeHover={onNodeHover}\n selectedNodeId={selectedNodeId}\n onSelectedNodeChange={onSelectedNodeChange}\n wheelZoom={wheelZoom}\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...hostPanel}\n />\n );\n}\n","\"use client\";\n\nimport { useCallback, useMemo } from \"react\";\nimport {\n TrackListOriginType, TracksFailureAlreadyReportedError, useTrackList, GenreCatalogueCountsSchema,\n defaultGenreMusicSelection, genreMusicSelectionKey,\n type GenreMusicSelection,\n type CriteriaPlaylistMinimum, type CriteriaPlaylistSimple, type TrackBase,\n type TrackListOriginFromCriteriaPlaylist,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport { AppError, ErrorCode, type Scope } from \"@behindthemusictree/app-kit/transport\";\nimport InternalErrorPopup from \"../../popup/InternalErrorPopup\";\n\nexport type PlayableGenrePlaylistInput = CriteriaPlaylistMinimum & { criteria?: CriteriaPlaylistSimple[\"criteria\"] };\n/** The playlist loaded in the player; `selectionKey` is `genreMusicSelectionKey(selection).join()`, empty without a selection. */\nexport type PlayingGenrePlaylist = { uuid: string; selectionKey: string };\nexport type GenrePlaylistPlayback = {\n playing: PlayingGenrePlaylist | null;\n /**\n * Plays `genrePlaylist`; `selection` overrides the default coverage of a reference genre. Never rejects: connectivity\n * errors reach the global popup through the backend request layer, any other failure is shown here with its real code.\n */\n play: (genrePlaylist: PlayableGenrePlaylistInput, selection?: GenreMusicSelection) => Promise<void>;\n};\nexport type UseGenrePlaylistPlaybackOptions = {\n scope: Scope;\n genrePlaylists: CriteriaPlaylistSimple[];\n artist?: { uuid: string; name: string } | null;\n};\n\nexport function useGenrePlaylistPlayback<T extends TrackBase = TrackBase>({\n scope, genrePlaylists, artist = null,\n}: UseGenrePlaylistPlaybackOptions): GenrePlaylistPlayback {\n const { trackList, playNewTrackListFromGenrePlaylist } = useTrackList<T>();\n const { showPopup } = usePopup();\n const origin = trackList?.origin;\n const playing = useMemo<PlayingGenrePlaylist | null>(() => {\n if (!origin || origin.type !== TrackListOriginType.GENRE_PLAYLIST || origin.scope !== scope) return null;\n const playlistOrigin = origin as TrackListOriginFromCriteriaPlaylist;\n if (playlistOrigin.artistUuid !== artist?.uuid) return null;\n const playlist = genrePlaylists.find((item) => item.uuid === origin.uuid) ?? playlistOrigin.criteriaPlaylist;\n const expected = scope === \"reference\" && playlist && !(\"criteria\" in playlist && playlist.criteria === null)\n ? defaultGenreMusicSelection(GenreCatalogueCountsSchema.parse(playlist)) : undefined;\n return { uuid: origin.uuid, selectionKey: genreMusicSelectionKey(playlistOrigin.selection ?? expected).join() };\n }, [origin, artist, genrePlaylists, scope]);\n\n const play = useCallback(async (playlist: PlayableGenrePlaylistInput, requested?: GenreMusicSelection) => {\n if (artist && !playlist.criteria) return;\n try {\n const selection = scope === \"reference\" && playlist.criteria !== null\n ? requested ?? defaultGenreMusicSelection(GenreCatalogueCountsSchema.parse(playlist)) : undefined;\n await (selection || artist\n ? playNewTrackListFromGenrePlaylist(playlist, scope, { selection, ...(artist && { artistUuid: artist.uuid }) })\n : playNewTrackListFromGenrePlaylist(playlist, scope));\n } catch (error) {\n console.error(\"Failed to load genre playlist tracks:\", error);\n if (error instanceof TracksFailureAlreadyReportedError) return;\n showPopup(<InternalErrorPopup errorCode={error instanceof AppError ? error.code : ErrorCode.CLIENT_UNKNOWN} />);\n }\n }, [artist, scope, playNewTrackListFromGenrePlaylist, showPopup]);\n\n return useMemo(() => ({ playing, play }), [playing, play]);\n}\n","\"use client\";\n\nimport { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { useCallback, useMemo, type ReactNode } from \"react\";\nimport {\n GenreTreeWheel,\n type GenreTreeViewport,\n type GenreTreeProps,\n type GenreTreeAction,\n type GenreTreeNode,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaMinimum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { HostPanelProps } from \"./hostPanelProps\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./useGenrePlaylistPlayback\";\nimport type { GenreTreeSizeMetric } from \"./size-metric\";\nimport { toTreeNodes } from \"./toTreeNodes\";\n\nexport type GenrePlaylistTreeWheelProps<T extends TrackBase> = {\n scope: Scope;\n className?: string;\n genrePlaylists: CriteriaPlaylistSimple[];\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n onNodeClick?: (node: GenreTreeNode) => void;\n onNodeHover?: (node: GenreTreeNode) => void;\n /** Overrides which node is shown highlighted, e.g. from a search selection. */\n selectedNodeId?: string | null;\n /** Fires when a user action changes the info panel's node, or `null` when it is closed. */\n onSelectedNodeChange?: (node: GenreTreeNode | null) => void;\n /** When true, suppresses per-node create/rename affordances. Defaults to false. */\n readOnly?: boolean;\n /** When false, clicking a chip still selects its root, but the wheel doesn't spin to the\n * anchor. Defaults to true. */\n allowWheelRotation?: boolean;\n /** What node size is proportional to; defaults to the song count. */\n sizeMetric?: GenreTreeSizeMetric;\n /** Rendered in the floating controls, beside the zoom buttons. */\n floatingControlsLeading?: ReactNode;\n /** Shows the tree's busy indicator while the data behind it is changing. */\n busy?: boolean;\n /** Mount-only seed for the pan/zoom, replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Runtime viewport restoration request. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** What node play buttons play; defaults to each node's whole genre playlist. */\n playback?: GenrePlaylistPlayback;\n /** The open artist's footprint; nodes outside it are drawn muted. */\n focusUuids?: ReadonlySet<string>;\n} & HostPanelProps;\n\nexport default function GenrePlaylistTreeWheel<T extends TrackBase>({\n scope,\n className,\n genrePlaylists,\n handleGenreCreationAction,\n handleGenreRenameAction,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n readOnly = false,\n allowWheelRotation,\n sizeMetric = \"songs\",\n floatingControlsLeading,\n busy,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n playback,\n focusUuids,\n ...hostPanel\n}: GenrePlaylistTreeWheelProps<T>) {\n const { isPlaying, setIsPlaying } = usePlayer();\n const defaultPlayback = useGenrePlaylistPlayback<T>({ scope, genrePlaylists });\n const { playing, play } = playback ?? defaultPlayback;\n const playingNodeId = playing?.uuid ?? null;\n\n const nodes = useMemo(\n () => toTreeNodes(genrePlaylists, sizeMetric, focusUuids),\n [genrePlaylists, sizeMetric, focusUuids],\n );\n\n const handlePlayPause = useCallback(\n (nodeId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);\n if (!genrePlaylist) return;\n\n if (nodeId === playingNodeId) {\n setIsPlaying(!isPlaying);\n return;\n }\n\n if (genrePlaylistTrackCount(genrePlaylist) === 0) {\n return;\n }\n\n void play(genrePlaylist);\n },\n [\n genrePlaylists,\n playingNodeId,\n isPlaying,\n setIsPlaying,\n play,\n ],\n );\n\n const handleAddChild = useCallback(\n (parentId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === parentId);\n if (!genrePlaylist?.criteria) return;\n handleGenreCreationAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreCreationAction],\n );\n\n const handleRenameRequest = useCallback(\n (node: GenreTreeNode) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === node.id);\n if (!genrePlaylist?.criteria) return;\n handleGenreRenameAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreRenameAction],\n );\n\n const handleDeleteRequest = useCallback((node: GenreTreeNode) => {\n if (confirm(`Are you sure you want to delete \"${node.name}\"?`)) {\n // TODO: Implement delete genre\n }\n }, []);\n\n return (\n <GenreTreeWheel\n className={className}\n nodes={nodes}\n playingNodeId={playingNodeId}\n playState={isPlaying ? \"playing\" : \"paused\"}\n onPlayPause={handlePlayPause}\n onAddChild={readOnly ? undefined : handleAddChild}\n onRenameRequest={readOnly ? undefined : handleRenameRequest}\n onDeleteRequest={readOnly ? undefined : handleDeleteRequest}\n additionalActions={additionalActions}\n onNodeClick={onNodeClick}\n onNodeHover={onNodeHover}\n selectedNodeId={selectedNodeId}\n onSelectedNodeChange={onSelectedNodeChange}\n allowWheelRotation={allowWheelRotation}\n floatingControlsLeading={floatingControlsLeading}\n busy={busy}\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...hostPanel}\n />\n );\n}\n","\"use client\";\n\nimport { genrePlaylistTrackCount } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { useCallback, useMemo, type ReactNode } from \"react\";\nimport {\n GenreTreeOutline,\n GenreTreeWheelRadialPopCore,\n type GenreTreeViewport,\n type GenreTreeProps,\n type FocusChangeReason,\n type GenreTreeAction,\n type GenreTreeNode,\n} from \"@behindthemusictree/genre-tree-view\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { CriteriaPlaylistSimple } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaMinimum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { HostPanelProps } from \"./hostPanelProps\";\nimport { useGenrePlaylistPlayback, type GenrePlaylistPlayback } from \"./useGenrePlaylistPlayback\";\nimport type { GenreTreeSizeMetric } from \"./size-metric\";\nimport { toTreeNodes } from \"./toTreeNodes\";\n\n/** Pop-core focus is controlled-only: pass both props or neither. Ignored in outline mode. */\nexport type GenreFocusProps =\n | { focusGenreUuid?: undefined; onFocusGenreChange?: undefined }\n | {\n /** Zooms the pop-core wheel into this genre's subtree. An unknown or non-zoomable uuid shows\n * the whole tree and fires `onFocusGenreChange(null, \"rejected\")`. */\n focusGenreUuid: string | null;\n /** Fires with the genre to focus and why: `\"zoom-in\"` / `\"back\"` (parent) / `\"previous\"` /\n * `\"root\"` from the user's zoom controls, `\"search\"` when a selection outside the zoom refocuses\n * to its top-level root (null for Mainstream Pop), and\n * `\"rejected\"` when an invalid `focusGenreUuid` is reset to null. */\n onFocusGenreChange: (uuid: string | null, reason: FocusChangeReason) => void;\n };\n\nexport type GenrePlaylistTreeWheelRadialPopCoreProps<T extends TrackBase> = {\n scope: Scope;\n className?: string;\n genrePlaylists: CriteriaPlaylistSimple[];\n handleGenreCreationAction: (parent: CriteriaMinimum | null) => void;\n handleGenreRenameAction: (genre: CriteriaMinimum) => void;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n onNodeClick?: (node: GenreTreeNode) => void;\n onNodeHover?: (node: GenreTreeNode) => void;\n /** Overrides which node is shown highlighted, e.g. from a search selection. */\n selectedNodeId?: string | null;\n /** Fires when a user action changes the info panel's node, or `null` when it is closed. */\n onSelectedNodeChange?: (node: GenreTreeNode | null) => void;\n /** When true, suppresses per-node create/rename affordances. Defaults to false. */\n readOnly?: boolean;\n /** When false, clicking a chip still selects its root, but the ring doesn't spin to the\n * landing angle. Defaults to true. */\n allowWheelRotation?: boolean;\n /** What node size is proportional to; defaults to the song count. */\n sizeMetric?: GenreTreeSizeMetric;\n /** Rendered in the floating controls, beside the zoom buttons. */\n floatingControlsLeading?: ReactNode;\n /** Shows the tree's busy indicator while the data behind it is changing; ignored in outline mode. */\n busy?: boolean;\n /** When true, renders the same forest as GenreTreeOutline's nested-list text view instead of\n * the radial wheel. Defaults to false. */\n outline?: boolean;\n /** Mount-only seed for the pan/zoom, replacing the initial fit. */\n defaultViewport?: GenreTreeViewport;\n /** Runtime viewport restoration request. */\n viewportRestore?: GenreTreeProps[\"viewportRestore\"];\n /** Fires after a user-driven pan/zoom settles. */\n onViewportChange?: (viewport: GenreTreeViewport) => void;\n /** What node play buttons play; defaults to each node's whole genre playlist. */\n playback?: GenrePlaylistPlayback;\n /** The open artist's footprint; nodes outside it are drawn muted. */\n focusUuids?: ReadonlySet<string>;\n} & GenreFocusProps &\n HostPanelProps;\n\nexport default function GenrePlaylistTreeWheelRadialPopCore<T extends TrackBase>(\n props: GenrePlaylistTreeWheelRadialPopCoreProps<T>,\n) {\n const {\n scope,\n className,\n genrePlaylists,\n handleGenreCreationAction,\n handleGenreRenameAction,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n readOnly = false,\n allowWheelRotation,\n sizeMetric = \"songs\",\n floatingControlsLeading,\n busy,\n outline = false,\n defaultViewport,\n viewportRestore,\n onViewportChange,\n playback,\n } = props;\n const focus: GenreFocusProps = props;\n const hostPanel: HostPanelProps = {\n obscuredInset: props.obscuredInset,\n onNodeStyleResolverChange: props.onNodeStyleResolverChange,\n };\n const { isPlaying, setIsPlaying } = usePlayer();\n const defaultPlayback = useGenrePlaylistPlayback<T>({ scope, genrePlaylists });\n const { playing, play } = playback ?? defaultPlayback;\n const playingNodeId = playing?.uuid ?? null;\n\n const nodes = useMemo(() => toTreeNodes(genrePlaylists, sizeMetric, props.focusUuids), [genrePlaylists, sizeMetric, props.focusUuids]);\n\n const handlePlayPause = useCallback(\n (nodeId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);\n if (!genrePlaylist) return;\n\n if (nodeId === playingNodeId) {\n setIsPlaying(!isPlaying);\n return;\n }\n\n if (genrePlaylistTrackCount(genrePlaylist) === 0) {\n return;\n }\n\n void play(genrePlaylist);\n },\n [genrePlaylists, playingNodeId, isPlaying, setIsPlaying, play],\n );\n\n const handleAddChild = useCallback(\n (parentId: string) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === parentId);\n if (!genrePlaylist?.criteria) return;\n handleGenreCreationAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreCreationAction],\n );\n\n const handleRenameRequest = useCallback(\n (node: GenreTreeNode) => {\n const genrePlaylist = genrePlaylists.find((g) => g.uuid === node.id);\n if (!genrePlaylist?.criteria) return;\n handleGenreRenameAction(genrePlaylist.criteria);\n },\n [genrePlaylists, handleGenreRenameAction],\n );\n\n const handleDeleteRequest = useCallback((node: GenreTreeNode) => {\n if (confirm(`Are you sure you want to delete \"${node.name}\"?`)) {\n // TODO: Implement delete genre\n }\n }, []);\n\n const treeProps = {\n className,\n nodes,\n playingNodeId,\n playState: isPlaying ? (\"playing\" as const) : (\"paused\" as const),\n onPlayPause: handlePlayPause,\n onAddChild: readOnly ? undefined : handleAddChild,\n onRenameRequest: readOnly ? undefined : handleRenameRequest,\n onDeleteRequest: readOnly ? undefined : handleDeleteRequest,\n additionalActions,\n onNodeClick,\n onNodeHover,\n selectedNodeId,\n onSelectedNodeChange,\n ...hostPanel,\n };\n\n return outline ? (\n <GenreTreeOutline {...treeProps} />\n ) : (\n <GenreTreeWheelRadialPopCore\n {...treeProps}\n allowWheelRotation={allowWheelRotation}\n floatingControlsLeading={floatingControlsLeading}\n busy={busy}\n defaultViewport={defaultViewport}\n viewportRestore={viewportRestore}\n onViewportChange={onViewportChange}\n {...(focus.onFocusGenreChange\n ? { focusNodeId: focus.focusGenreUuid, onFocusChange: focus.onFocusGenreChange }\n : { focusNodeId: undefined, onFocusChange: undefined })}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type GenreTreeWheelHandoffProps = {\n skeleton: React.ReactNode;\n children: React.ReactNode;\n /** Called with `true` once `children` is revealed, and with `false` when the handoff unmounts. */\n onRevealedChange?: (revealed: boolean) => void;\n};\n\n/**\n * Keeps `skeleton` fully opaque over `children` for the first two animation frames after\n * `children` mounts, then cross-fades to `children`.\n *\n * `children` is one of genre-tree-view's wheel components (`GenreTreeWheel` /\n * `GenreTreeWheelRadialPopCore`), which compute their own pan/zoom \"fit to frame\" in a passive\n * effect (`hasInitialFitRef`) that runs *after* their first paint. Without this handoff, that\n * first paint — unfit, `translate(0,0) scale(1)` — is briefly visible the instant the skeleton is\n * swapped out, which reads as a flash/jump right as loading finishes. Two nested\n * `requestAnimationFrame` calls reliably span that effect's own render-commit-paint cycle, so\n * `children` has had time to begin layout before it is revealed. Viewport restoration waits for\n * measurable geometry independently of this visual handoff.\n *\n * Remounting this component (e.g. via a `key` change, or the parent unmounting/remounting the\n * branch that renders it) restarts the handoff, which is what's wanted any time `children` itself\n * is about to mount fresh and re-run its own fit-to-frame effect.\n */\nexport function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }: GenreTreeWheelHandoffProps) {\n const [revealed, setRevealed] = useState(false);\n const onRevealedChangeRef = useRef(onRevealedChange);\n onRevealedChangeRef.current = onRevealedChange;\n\n useEffect(() => {\n let innerFrame = 0;\n const outerFrame = requestAnimationFrame(() => {\n innerFrame = requestAnimationFrame(() => {\n setRevealed(true);\n onRevealedChangeRef.current?.(true);\n });\n });\n return () => {\n onRevealedChangeRef.current?.(false);\n cancelAnimationFrame(outerFrame);\n cancelAnimationFrame(innerFrame);\n };\n }, []);\n\n return (\n <div className=\"relative w-full h-full\">\n <div\n className=\"absolute inset-0 transition-opacity duration-150 ease-out\"\n style={{ opacity: revealed ? 1 : 0, pointerEvents: revealed ? \"auto\" : \"none\" }}\n aria-hidden={!revealed}\n >\n {children}\n </div>\n {!revealed && (\n <div className=\"absolute inset-0\" aria-hidden=\"true\">\n {skeleton}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useDeferredValue, useState, type ComponentType, type ReactNode } from \"react\";\nimport type { GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\nimport GenreSearch, { type GenreSearchProps } from \"./GenreSearch\";\nimport { useArtistSearchGroup, useSongSearchGroup, type SearchGroup } from \"./search\";\n\nexport interface GenreSearchGroupsProps {\n query: string;\n focused: boolean;\n onSelectGenre: (uuid: GenreUuid) => void;\n children: (groups: SearchGroup[]) => ReactNode;\n}\n\ntype Props = GenreSearchProps & {\n artistBaseUrl: () => string;\n songBaseUrl: () => string;\n onArtistSelect: Parameters<typeof useArtistSearchGroup>[2];\n onSongSelect: Parameters<typeof useSongSearchGroup>[2];\n artistSearch: boolean;\n songSearch: boolean;\n SearchGroups?: ComponentType<GenreSearchGroupsProps>;\n onSelectGenre: (uuid: GenreUuid) => void;\n};\n\n/** Keep typed query updates and remote results inside the search subtree. */\nexport function GenreTreeSearch({\n artistBaseUrl, songBaseUrl, onArtistSelect, onSongSelect, artistSearch, songSearch,\n SearchGroups, onSelectGenre, extraGroups = [], onQueryChange, onFocus, ...props\n}: Props) {\n const [query, setQuery] = useState(\"\");\n const [focused, setFocused] = useState(false);\n const deferredQuery = useDeferredValue(query);\n const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);\n const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);\n const render = (hostGroups: SearchGroup[]) => (\n <GenreSearch\n {...props}\n onQueryChange={(text) => {\n setQuery(text);\n onQueryChange?.(text);\n }}\n onFocus={() => {\n setFocused(true);\n onFocus?.();\n }}\n extraGroups={[...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group): group is SearchGroup => group !== undefined)}\n />\n );\n return SearchGroups\n ? <SearchGroups query={deferredQuery} focused={focused} onSelectGenre={onSelectGenre}>{render}</SearchGroups>\n : render([]);\n}\n","\"use client\";\n\nimport { ArrowLeft } from \"lucide-react\";\nimport { SEARCH_LEADING_BUTTON_CLASS } from \"@behindthemusictree/ui\";\n\nimport { CriteriaPlaylistSimple, useGenreSearch } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { SearchBox, type SearchGroup } from \"./search\";\n\n/** @deprecated Use `SearchGroup`. */\nexport type GenreSearchExtraGroup = SearchGroup;\n\nexport type GenreSearchProps<T extends CriteriaPlaylistSimple = CriteriaPlaylistSimple> = {\n genrePlaylists: T[];\n onSelect: (genrePlaylist: T) => void;\n /** Name of the currently selected genre; fills the input whenever it changes. */\n selectedName?: string | null;\n /** When set, renders a \"Previous\" button left of the text and makes room for it. */\n onPrevious?: () => void;\n /** Called by the clear button, after it empties the input. */\n onClear?: () => void;\n /** Forces the clear button on or off; by default it shows while the input has something to clear. */\n showClear?: boolean;\n clearLabel?: string;\n placeholder?: string;\n /** Called with what the user types, and with \"\" on clear or pick; never when `selectedName` refills the input. */\n onQueryChange?: (query: string) => void;\n /** Further result groups (places, artists, songs) the host resolves from `onQueryChange`. */\n extraGroups?: SearchGroup[];\n /** Called when the input gains focus. */\n onFocus?: () => void;\n};\n\nexport default function GenreSearch<T extends CriteriaPlaylistSimple = CriteriaPlaylistSimple>({\n genrePlaylists,\n onSelect,\n selectedName = null,\n onClear,\n showClear,\n clearLabel,\n onPrevious,\n placeholder,\n onQueryChange,\n extraGroups = [],\n onFocus,\n}: GenreSearchProps<T>) {\n const { query, setQuery, results, canClear, clear, select } = useGenreSearch({\n genrePlaylists,\n onSelect,\n selectedName,\n onClear,\n });\n\n const active = query !== \"\" && query !== selectedName;\n const hasExtras = extraGroups.length > 0;\n const label = hasExtras ? \"Search\" : \"Search a genre\";\n\n const groups: SearchGroup[] = [\n {\n key: \"genres\",\n label: hasExtras ? \"Genres\" : undefined,\n items: results.map((genrePlaylist) => ({\n key: genrePlaylist.uuid,\n content: (\n <>\n {genrePlaylist.name}\n {genrePlaylist.isUmbrella && (\n <span className=\"ml-2 text-caption italic text-[var(--color-text-muted)]\">umbrella</span>\n )}\n </>\n ),\n onSelect: () => select(genrePlaylist),\n })),\n },\n ...extraGroups.map((group) =>\n active\n ? group\n : { ...group, items: [], status: \"\", loading: false },\n ),\n ];\n\n return (\n <div className=\"genre-search w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 max-md:w-full\">\n <SearchBox\n label={label}\n placeholder={placeholder}\n value={query}\n onValueChange={(value) => {\n setQuery(value);\n onQueryChange?.(value);\n }}\n groups={groups}\n onPicked={(groupKey) => {\n if (groupKey !== \"genres\") setQuery(\"\");\n onQueryChange?.(\"\");\n }}\n clearLabel={clearLabel}\n onClear={\n (showClear ?? canClear)\n ? () => {\n clear();\n onQueryChange?.(\"\");\n }\n : undefined\n }\n leading={\n onPrevious && (\n <button type=\"button\" aria-label=\"Previous\" title=\"Previous\" className={SEARCH_LEADING_BUTTON_CLASS} onClick={onPrevious}>\n <ArrowLeft aria-hidden=\"true\" className=\"h-4 w-4\" />\n </button>\n )\n }\n onFocus={onFocus}\n />\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\nimport { SearchCombobox } from \"@behindthemusictree/ui\";\n\nimport type { SearchGroup } from \"./SearchGroup\";\n\nexport type SearchBoxProps = {\n /** Accessible name of the input and the list. */\n label: string;\n placeholder?: string;\n value: string;\n onValueChange: (value: string) => void;\n groups: SearchGroup[];\n /** Called after the group item is picked and the list closed. */\n onPicked?: (groupKey: string, itemKey: string) => void;\n /** Shows the clear button when set. */\n onClear?: () => void;\n clearLabel?: string;\n /** An action left of the text, e.g. a Previous button. */\n leading?: ReactNode;\n className?: string;\n /** Called when the input gains focus, e.g. to load an index lazily. */\n onFocus?: () => void;\n};\n\n/** A search pill over any number of result groups; picking an item calls that item's `onSelect`. */\nexport default function SearchBox({\n label,\n placeholder,\n value,\n onValueChange,\n groups,\n onPicked,\n onClear,\n clearLabel,\n leading,\n className,\n onFocus,\n}: SearchBoxProps) {\n const [open, setOpen] = useState(false);\n const loading = groups.some((group) => group.loading);\n const status = groups\n .map((group) => group.status)\n .filter(Boolean)\n .join(\". \");\n\n const handlePick = (groupKey: string, itemKey: string) => {\n setOpen(false);\n groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();\n onPicked?.(groupKey, itemKey);\n };\n\n return (\n <div className={className} onFocusCapture={onFocus}>\n <SearchCombobox\n ariaLabel={label}\n listLabel={`${label} results`}\n value={value}\n placeholder={placeholder ?? `${label}…`}\n groups={groups.map((group) => ({\n key: group.key,\n label: group.label,\n options: group.items.map((item) => ({ key: item.key, content: item.content })),\n }))}\n open={open}\n onOpenChange={setOpen}\n onValueChange={onValueChange}\n onPick={handlePick}\n status={status}\n loading={loading}\n onClear={onClear}\n clearLabel={clearLabel}\n leading={leading}\n inputClassName=\"focus-visible:ring-0\"\n />\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\n\nexport type SearchGroupItem = { key: string; content: ReactNode; onSelect: () => void };\n\n/** One headed list of results in a `SearchBox`, resolved by the host or by a group hook. */\nexport type SearchGroup = {\n key: string;\n /** Heading of the group; omitted when it is the only one. */\n label?: string;\n items: SearchGroupItem[];\n /** Announced politely, e.g. \"No artists found\". */\n status?: string;\n /** Shows a spinner in place of the search icon while this group resolves. */\n loading?: boolean;\n};\n\nexport const SEARCH_FAILED_STATUS = \"Search failed\";\n\n/** \"Search failed\" on error, \"No <noun> found\" once settled and empty, else \"\". */\nexport const searchStatus = (\n state: { isError: boolean; settled: boolean },\n count: number,\n noun: string,\n): string => (state.isError ? SEARCH_FAILED_STATUS : state.settled && count === 0 ? `No ${noun} found` : \"\");\n","\"use client\";\n\nimport { useArtistSearch, type ArtistSearchResult } from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { searchStatus, type SearchGroup } from \"./SearchGroup\";\n\nexport function useArtistSearchGroup(\n getBaseUrl: () => string,\n text: string,\n onSelect: (artist: ArtistSearchResult) => void,\n enabled = true,\n): SearchGroup | undefined {\n const search = useArtistSearch(getBaseUrl, enabled ? text : \"\");\n if (!enabled) return undefined;\n return {\n key: \"artists\",\n label: \"Artists\",\n items: search.artists.map((artist) => ({\n key: artist.uuid,\n content: (\n <>\n <span className=\"block truncate font-medium\">\n {artist.name}\n {artist.disambiguation && (\n <span className=\"font-normal text-[var(--color-neutral-500)]\"> · {artist.disambiguation}</span>\n )}\n </span>\n {artist.matchedAlias && (\n <span className=\"block truncate text-caption text-[var(--color-neutral-500)]\">also known as {artist.matchedAlias}</span>\n )}\n </>\n ),\n onSelect: () => onSelect(artist),\n })),\n status: searchStatus(search, search.artists.length, \"artists\"),\n loading: search.pending,\n };\n}\n","\"use client\";\n\nimport {\n isSongSearchResultPlayable,\n useSongSearch,\n type SongSearchResult,\n} from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { searchStatus, type SearchGroup } from \"./SearchGroup\";\n\nexport function useSongSearchGroup(\n getBaseUrl: () => string,\n text: string,\n onSelect: (song: SongSearchResult) => void,\n enabled = true,\n): SearchGroup | undefined {\n const search = useSongSearch(getBaseUrl, enabled ? text : \"\");\n if (!enabled) return undefined;\n return {\n key: \"songs\",\n label: \"Songs\",\n items: search.songs.map((song) => ({\n key: song.uuid,\n content: (\n <span className={isSongSearchResultPlayable(song) ? undefined : \"opacity-60\"}>\n <span className=\"block truncate font-medium\">{song.title}</span>\n <span className=\"block truncate text-caption text-[var(--color-neutral-500)]\">\n {[song.artists.map((artist) => artist.name).join(\", \"), song.genre?.name ?? \"No genre\"].filter(Boolean).join(\" · \")}\n </span>\n </span>\n ),\n onSelect: () => onSelect(song),\n })),\n status: searchStatus(search, search.songs.length, \"songs\"),\n loading: search.pending,\n };\n}\n","\"use client\";\n\nimport {\n useGenreRemoteSearch,\n type GenreSearchResult,\n type UseGenreRemoteSearchOptions,\n} from \"@behindthemusictree/app-kit/genre-tree\";\n\nimport { searchStatus, type SearchGroup } from \"./SearchGroup\";\n\nexport type UseGenreRemoteSearchGroupOptions = UseGenreRemoteSearchOptions & {\n key?: string;\n label?: string;\n /** Drops hits the host already lists elsewhere. */\n filter?: (genre: GenreSearchResult) => boolean;\n /** Extra secondary text per hit, e.g. the region. */\n describe?: (genre: GenreSearchResult) => string | undefined;\n};\n\n/** Genres from the API's ranked `genres/search/`, rendered with the umbrella tag and the tree they live in. */\nexport function useGenreRemoteSearchGroup(\n getBaseUrl: () => string,\n text: string,\n onSelect: (genre: GenreSearchResult) => void,\n { key = \"genres\", label = \"Genres\", filter, describe, ...options }: UseGenreRemoteSearchGroupOptions = {},\n): SearchGroup {\n const search = useGenreRemoteSearch(getBaseUrl, text, options);\n const genres = filter ? search.genres.filter(filter) : search.genres;\n return {\n key,\n label,\n items: genres.map((genre) => ({\n key: genre.uuid,\n content: (\n <>\n <span className=\"block truncate font-medium\">\n {genre.name}\n {genre.isUmbrella && <span className=\"ml-2 text-caption font-normal italic text-[var(--color-text-muted)]\">umbrella</span>}\n </span>\n <span className=\"block truncate text-caption text-[var(--color-neutral-500)]\">\n {describe?.(genre) ?? `${genre.treeName} · ${genre.root.name}`}\n </span>\n </>\n ),\n onSelect: () => onSelect(genre),\n })),\n status: searchStatus(search, genres.length, \"genres\"),\n loading: search.pending,\n };\n}\n","\"use client\";\n\nimport { useMemo, type ReactNode, type ComponentProps } from \"react\";\nimport {\n GenreNodeAncestors,\n GenreNodeFamily,\n getGenreTreeColor,\n getTextColorOnFill,\n TEXT_COLOR,\n tintSurface,\n type GenreNodeStyle,\n type GenreTreeNode,\n type InfoPanelChild,\n} from \"@behindthemusictree/genre-tree-view\";\nimport { DetailPanel, IconButton, Skeleton } from \"@behindthemusictree/ui\";\nimport { Maximize2, Minimize2 } from \"lucide-react\";\n\nimport {\n useFetchGenreDetail,\n genreMusicCount,\n GenrePlaylistSummarySchema,\n GenreCatalogueCountsSchema,\n CriteriaMinimumSchema,\n type CriteriaPlaylistSimple,\n type CriteriaMinimum,\n type CriteriaOverview,\n type GenreUuid,\n GenreUuidSchema,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\n\nimport { GenreInfoPanelBody, type GenreInfoPanelBodyProps } from \"./GenreInfoPanelBody\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport { useGenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\n\nexport type GenreDetailPanelProps<O extends CriteriaOverview> = {\n /** May be a raw URL value: one that names no genre renders \"Genre not found\". */\n genreUuid: string;\n scope: Scope;\n getBackendBaseUrl: () => string;\n onClose: () => void;\n /** Fired with the uuid of a family or ancestor chip the user picked. */\n onSelectGenre: (genreUuid: GenreUuid) => void;\n /** When set, the panel offers \"Focus\". */\n onZoomIn?: () => void;\n /** Absolute or relative URL that shares this genre; the share action shows only when set. */\n shareUrl?: string;\n shareTarget?: GenreTreeShareTarget;\n collapsed?: boolean;\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** Tab on the panel's inner edge, for hosts that hide and show the panel. */\n edgeTab?: ComponentProps<typeof DetailPanel>[\"edgeTab\"];\n extras?: GenreInfoPanelBodyProps<O>[\"extras\"];\n /** The host's search field shows this genre's name and closes the panel. */\n titleInSearch?: boolean;\n};\n\n// Relatives from the detail endpoint carry no song count, so the family dots share one size.\nconst RELATIVE_ITEM_COUNT = 1;\n\nfunction toNode(genre: CriteriaMinimum, parentId: string | null): GenreTreeNode {\n return {\n id: genre.uuid,\n parentId,\n name: genre.name,\n itemCount: RELATIVE_ITEM_COUNT,\n side: genre.side ?? undefined,\n wikidataId: genre.wikidataId,\n };\n}\n\ntype GenreDetailContentOptions<O extends CriteriaOverview> = {\n genreUuid: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n onSelectGenre: (uuid: GenreUuid) => void;\n extras?: GenreInfoPanelBodyProps<O>[\"extras\"];\n band?: Partial<GenreInfoPanelBodyProps<O>[\"band\"]>;\n playback?: GenreInfoPanelBodyProps<O>[\"playback\"];\n trailing?: ReactNode;\n genrePlaylist?: CriteriaPlaylistSimple;\n expanded?: boolean;\n /** How the mounted tree draws this genre and its relatives, by genre uuid; genres it omits fall back to the root color. */\n treeStyles?: ReadonlyMap<GenreUuid, GenreNodeStyle>;\n};\n\n/** Shared entity data and content; the host owns the panel shell and placement. */\nexport function useGenreDetailContent<O extends CriteriaOverview>({\n genreUuid, scope, getBackendBaseUrl, onSelectGenre, extras, band, playback: hostPlayback, trailing, genrePlaylist: hostPlaylist, expanded, treeStyles,\n}: GenreDetailContentOptions<O>) {\n const result = useFetchGenreDetail(genreUuid, scope, getBackendBaseUrl);\n const detail = result.status === \"success\" ? result.genre : undefined;\n const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });\n const playback = hostPlayback ?? defaultPlayback;\n\n const view = useMemo(() => {\n if (!detail) return null;\n const rootColor = getGenreTreeColor(detail.root.wikidataId);\n const relative = (genre: CriteriaMinimum, parentId: string | null): InfoPanelChild => ({\n node: toNode(genre, parentId),\n ...(treeStyles?.get(genre.uuid) ?? { fill: tintSurface(rootColor), textColor: TEXT_COLOR }),\n });\n const ancestors = [...detail.ascendants].sort((a, b) => b.degree - a.degree);\n const own = treeStyles?.get(detail.uuid) ?? { fill: rootColor, textColor: getTextColorOnFill(rootColor) };\n return {\n node: {\n id: detail.uuid,\n parentId: detail.parent?.uuid ?? null,\n name: detail.name,\n itemCount: scope === \"reference\" ? genreMusicCount(detail.criteriaPlaylist ? GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist) : GenreCatalogueCountsSchema.parse(detail.catalogue)) : detail.tracksCount,\n wikidataId: detail.wikidataId,\n } satisfies GenreTreeNode,\n fill: own.fill,\n textColor: own.textColor,\n parentNode: detail.parent ? relative(detail.parent, null) : null,\n childNodes: detail.children.map((child) => relative(child, detail.uuid)),\n ancestorNodes: ancestors.map(({ ascendant }, index) =>\n relative(ascendant, index === 0 ? null : ancestors[index - 1].ascendant.uuid),\n ),\n };\n }, [detail, scope, treeStyles]);\n\n if (result.status === \"not-found\") return {\n name: null,\n title: \"Genre not found\",\n content: <p className=\"text-[var(--color-text-muted)]\">This genre does not exist.</p>,\n };\n if (result.status === \"error\") return {\n name: null,\n title: \"Genre unavailable\",\n content: <p role=\"alert\" className=\"text-body text-[var(--color-text)]\">This genre could not be loaded.</p>,\n };\n if (!detail || !view) return {\n name: null,\n title: \"Loading genre…\",\n content: <div className=\"flex flex-col gap-3\" aria-busy=\"true\" data-testid=\"genre-detail-panel-skeleton\">\n <Skeleton className=\"h-6 w-2/3\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-3/4\" />\n </div>,\n };\n\n const selectGenre = (nodeId: string) => onSelectGenre(GenreUuidSchema.parse(nodeId));\n const family = (\n <GenreNodeFamily\n node={view.node}\n fill={view.fill}\n textColor={view.textColor}\n parentNode={view.parentNode}\n childNodes={view.childNodes}\n onSelectNode={selectGenre}\n />\n );\n const ancestors = (\n <GenreNodeAncestors\n node={view.node}\n fill={view.fill}\n textColor={view.textColor}\n ancestorNodes={view.ancestorNodes}\n onSelectNode={selectGenre}\n />\n );\n\n return {\n name: detail.name,\n title: detail.name,\n headerAccent: { background: view.fill, color: view.textColor },\n aside: expanded ? ancestors : undefined,\n content: <>\n <GenreInfoPanelBody<O>\n family={<>{family}{!expanded && ancestors}</>}\n genreUuid={detail.uuid}\n genrePlaylist={hostPlaylist ?? (detail.criteriaPlaylist === null ? null : scope === \"reference\" ? { ...GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist), criteria: CriteriaMinimumSchema.parse(detail) } : { ...detail.criteriaPlaylist, criteria: CriteriaMinimumSchema.parse(detail), tracksCount: detail.tracksCount })}\n catalogue={detail.catalogue}\n wikidataId={detail.wikidataId}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n playback={playback}\n band={{ node: view.node, ...band, shareTarget: band?.shareTarget?.kind === \"genre\" ? { ...band.shareTarget, name: detail.name } : band?.shareTarget }}\n extras={extras}\n />\n {trailing}\n </>,\n };\n}\n\nexport function GenreDetailPanel<O extends CriteriaOverview>({\n genreUuid, scope, getBackendBaseUrl, onClose, onSelectGenre, onZoomIn,\n shareUrl, shareTarget, collapsed, expanded, onExpandedChange, edgeTab, extras, titleInSearch,\n}: GenreDetailPanelProps<O>) {\n const panel = useGenreDetailContent({\n genreUuid, scope, getBackendBaseUrl, onSelectGenre, extras, expanded,\n band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : undefined },\n });\n return (\n <DetailPanel side=\"left\" title={panel.title} headerAccent={panel.headerAccent}\n onClose={onClose} collapsed={collapsed} expanded={expanded}\n onExpandedChange={onExpandedChange} edgeTab={edgeTab} aside={panel.aside} titleInSearch={titleInSearch}\n headerActions={onExpandedChange ? <IconButton aria-label={expanded ? \"Shrink panel\" : \"Extend panel\"} onClick={() => onExpandedChange(!expanded)}>\n {expanded ? <Minimize2 aria-hidden=\"true\" className=\"h-4 w-4\" /> : <Maximize2 aria-hidden=\"true\" className=\"h-4 w-4\" />}\n </IconButton> : undefined}\n >\n {panel.content}\n </DetailPanel>\n );\n}\n","\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport {\n defaultGenreMusicSelection,\n GenreCatalogueCountsSchema,\n type GenreCatalogueCounts,\n type GenrePlaylistSummary,\n type CriteriaOverview,\n type CriteriaMinimum,\n type CriteriaPlaylistMinimum,\n type GenreUuid,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\n\nimport GenreActionBand from \"./GenreActionBand\";\nimport GenrePlayActions from \"./GenrePlayActions\";\nimport { GenreDetailExtras, type GenreDetailExtrasProps } from \"./GenreDetailExtras\";\nimport type { GenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\n\n/** What the action band reads of a genre's playlist: enough to play it and to know whether it can be. */\nexport type PlayableGenrePlaylist = ((CriteriaPlaylistMinimum & { tracksCount: number }) | GenrePlaylistSummary) & { criteria?: CriteriaMinimum | null };\n\ntype GenreNodeActionBandProps = Omit<ComponentProps<typeof GenreActionBand>, \"playActions\"> & {\n genrePlaylist: PlayableGenrePlaylist;\n playback: GenrePlaylistPlayback;\n};\n\nexport function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }: GenreNodeActionBandProps) {\n return <GenreActionBand {...bandProps} playActions={<GenrePlayActions genrePlaylist={genrePlaylist} playback={playback} />} />;\n}\n\nexport type GenreInfoPanelBodyProps<O extends CriteriaOverview> = {\n /** genre-tree-view's toolbar section, rendered first. */\n toolbar?: ReactNode;\n family: ReactNode;\n genreUuid: GenreUuid;\n catalogue?: GenreCatalogueCounts;\n genrePlaylist: PlayableGenrePlaylist | null;\n wikidataId?: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n playback: GenrePlaylistPlayback;\n /** Action band props other than play, which the body derives from `playback`. */\n band: Omit<GenreNodeActionBandProps, \"genrePlaylist\" | \"playback\">;\n extras?: Omit<\n GenreDetailExtrasProps<O>,\n \"family\" | \"genreUuid\" | \"genreName\" | \"genrePlaylist\" | \"wikidataId\" | \"scope\" | \"getBackendBaseUrl\"\n >;\n};\n\n/** The body of a genre's info panel: action band, then the genre's overview, family and tracks.\n * Shared by the tree's panel and the standalone GenreDetailPanel. */\nexport function GenreInfoPanelBody<O extends CriteriaOverview>({\n toolbar,\n family,\n genreUuid,\n genrePlaylist,\n catalogue,\n wikidataId,\n scope,\n getBackendBaseUrl,\n playback,\n band,\n extras,\n}: GenreInfoPanelBodyProps<O>) {\n const summary = scope === \"reference\" ? GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : undefined;\n const selection = summary ? defaultGenreMusicSelection(summary) : undefined;\n return (\n <>\n {toolbar}\n {genrePlaylist ? <GenreNodeActionBand {...band} genrePlaylist={genrePlaylist} playback={playback} /> : <GenreActionBand {...band} />}\n <GenreDetailExtras<O>\n {...extras}\n key={genreUuid}\n family={family}\n genreUuid={genreUuid}\n genrePlaylist={genrePlaylist}\n genreName={band.node.name}\n selection={selection}\n wikidataId={wikidataId}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n />\n </>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { ArrowLeftRight, MoveUpRight, Pencil, Plus, ZoomIn } from \"lucide-react\";\nimport { ActionBand, ActionButton, PanelBleed } from \"@behindthemusictree/ui\";\nimport type {\n GenreTreeAction,\n GenreTreeNode,\n} from \"@behindthemusictree/genre-tree-view\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport ShareActionButton from \"./ShareActionButton\";\n\nexport type GenreActionBandProps = {\n node: GenreTreeNode;\n /** Play buttons, shown first. */\n playActions?: ReactNode;\n /** When set, shows the \"Zoom in\" action. */\n onZoomIn?: () => void;\n /** When set, shows the \"Add\" (sub-genre) action. */\n onAddChild?: () => void;\n /** When set, shows the \"Rename\" action. */\n onRename?: () => void;\n /** When set, shows the \"Parent\" (change parent) action. */\n onChangeParent?: () => void;\n side?: \"core\" | \"pop\";\n /** When set, shows the \"Make pop\" / \"Make core\" action. */\n onToggleSide?: () => void;\n /** When set, disables the side toggle and explains why in its tooltip. */\n toggleSideDisabledReason?: string;\n additionalActions?: (node: GenreTreeNode) => GenreTreeAction[];\n shareTarget?: GenreTreeShareTarget;\n shareUrl?: string;\n};\n\ntype BandItem = {\n key: string;\n label: string;\n icon: ReactNode;\n onClick: (event: React.MouseEvent) => void;\n disabled?: boolean;\n title?: string;\n};\n\nexport default function GenreActionBand({\n node,\n playActions,\n onZoomIn,\n onAddChild,\n onRename,\n onChangeParent,\n side,\n onToggleSide,\n toggleSideDisabledReason,\n additionalActions,\n shareTarget,\n shareUrl,\n}: GenreActionBandProps) {\n const items: BandItem[] = [];\n const adminItems: BandItem[] = [];\n if (onZoomIn) {\n items.push({\n key: \"zoom-in\",\n label: \"Focus\",\n icon: <ZoomIn aria-hidden=\"true\" className=\"w-5 h-5\" />,\n onClick: onZoomIn,\n });\n }\n if (onAddChild) {\n adminItems.push({ key: \"add-child\", label: \"Add\", icon: <Plus aria-hidden=\"true\" className=\"w-5 h-5\" />, onClick: onAddChild });\n }\n if (onRename) {\n adminItems.push({ key: \"rename\", label: \"Rename\", icon: <Pencil aria-hidden=\"true\" className=\"w-5 h-5\" />, onClick: onRename });\n }\n if (onChangeParent) {\n adminItems.push({ key: \"change-parent\", label: \"Parent\", icon: <MoveUpRight aria-hidden=\"true\" className=\"w-5 h-5\" />, onClick: onChangeParent });\n }\n if (onToggleSide) {\n adminItems.push({\n key: \"toggle-side\",\n label: side === \"pop\" ? \"Make core\" : \"Make pop\",\n icon: <ArrowLeftRight aria-hidden=\"true\" className=\"w-5 h-5\" />,\n onClick: onToggleSide,\n disabled: !!toggleSideDisabledReason,\n title: toggleSideDisabledReason,\n });\n }\n for (const action of additionalActions?.(node) ?? []) {\n items.push({\n key: action.key,\n label: action.label(node),\n icon: action.icon(node),\n onClick: (event) => action.onClick(event, node),\n disabled: action.enabled ? !action.enabled(node) : false,\n });\n }\n const renderItems = (list: BandItem[]) =>\n list.map((item) => (\n <ActionButton key={item.key} icon={item.icon} label={item.label} disabled={item.disabled} title={item.title} onClick={item.onClick} />\n ));\n\n if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;\n\n return (\n <PanelBleed>\n <ActionBand\n className=\"genre-action-band\"\n section={{ title: \"Admin\", label: \"Admin actions\", children: renderItems(adminItems) }}\n >\n {playActions}\n {renderItems(items)}\n {shareTarget && shareUrl && <ShareActionButton target={shareTarget} url={shareUrl} />}\n </ActionBand>\n </PanelBleed>\n );\n}\n","\"use client\";\n\nimport { Share2 } from \"lucide-react\";\nimport { ActionButton } from \"@behindthemusictree/ui\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport SharePopup from \"./SharePopup\";\n\ntype ShareActionButtonProps = {\n target: GenreTreeShareTarget;\n url: string;\n};\n\nexport default function ShareActionButton({ target, url }: ShareActionButtonProps) {\n const { showPopup, hidePopup } = usePopup();\n\n const openSharePopup = () => {\n showPopup(<SharePopup target={target} url={url} onClose={hidePopup} />);\n };\n\n return (\n <ActionButton\n icon={<Share2 aria-hidden=\"true\" className=\"w-5 h-5\" />}\n label=\"Share\"\n aria-label={`Share ${target.name}`}\n title={`Share ${target.name}`}\n onClick={openSharePopup}\n />\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { Link2, Share2 } from \"lucide-react\";\nimport { FaWhatsapp } from \"react-icons/fa\";\nimport { SiGmail } from \"react-icons/si\";\nimport BasePopup from \"../popup/BasePopup\";\nimport Toast from \"../popup/Toast\";\nimport type { GenreTreeShareTarget } from \"./share\";\nimport ShareDestinationButton from \"./ShareDestinationButton\";\nimport SharePreviewCard from \"./SharePreviewCard\";\n\ntype SharePopupProps = {\n target: GenreTreeShareTarget;\n url: string;\n onClose: () => void;\n};\n\ntype CopyStatus = \"idle\" | \"failed\";\n\nfunction resolveAbsoluteUrl(url: string): string | undefined {\n try {\n const parsed = new URL(url, window.location.href);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\" ? parsed.href : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function copyText(text: string): Promise<boolean> {\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // Use the legacy copy path when clipboard access is denied or unavailable.\n }\n\n const input = document.createElement(\"textarea\");\n input.value = text;\n input.setAttribute(\"readonly\", \"\");\n input.style.position = \"fixed\";\n input.style.opacity = \"0\";\n document.body.append(input);\n input.select();\n\n try {\n return document.execCommand(\"copy\");\n } catch {\n return false;\n } finally {\n input.remove();\n }\n}\n\nexport default function SharePopup({ target, url, onClose }: SharePopupProps) {\n const [absoluteUrl, setAbsoluteUrl] = useState(url);\n const [copyStatus, setCopyStatus] = useState<CopyStatus>(\"idle\");\n const [canUseNativeShare, setCanUseNativeShare] = useState(false);\n const [shareError, setShareError] = useState<string | null>(null);\n const [toastId, setToastId] = useState(0);\n\n useEffect(() => {\n setAbsoluteUrl(resolveAbsoluteUrl(url) ?? \"\");\n setCopyStatus(\"idle\");\n setShareError(null);\n }, [url]);\n\n useEffect(() => {\n setCanUseNativeShare(typeof navigator !== \"undefined\" && typeof navigator.share === \"function\");\n }, []);\n\n const destinationUrls = useMemo(() => {\n if (!absoluteUrl) return null;\n const message = `${target.name} — ${absoluteUrl}`;\n return {\n whatsapp: `https://wa.me/?text=${encodeURIComponent(message)}`,\n gmail: `https://mail.google.com/mail/?view=cm&fs=1&su=${encodeURIComponent(`Share: ${target.name}`)}&body=${encodeURIComponent(message)}`,\n };\n }, [absoluteUrl, target.name]);\n\n const handleCopy = async () => {\n if (!absoluteUrl) {\n setCopyStatus(\"failed\");\n return;\n }\n setShareError(null);\n const copied = await copyText(absoluteUrl);\n setCopyStatus(copied ? \"idle\" : \"failed\");\n if (copied) setToastId((id) => id + 1);\n };\n\n const dismissToast = useCallback(() => setToastId(0), []);\n\n const handleNativeShare = async () => {\n if (!absoluteUrl || !navigator.share) return;\n setShareError(null);\n try {\n await navigator.share({ title: target.name, url: absoluteUrl });\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") return;\n setShareError(\"Could not open the share options.\");\n }\n };\n\n return (\n <>\n <BasePopup\n title=\"Share\"\n onClose={onClose}\n isDismissable\n trapFocus\n closeOnEscape\n closeOnBackdrop\n className=\"!w-full !max-w-[28rem] overflow-hidden !rounded-[2rem] !bg-[var(--color-surface)] shadow-2xl\"\n overlayClassName=\"!bg-black/50 p-4 backdrop-blur-[2px]\"\n titleClassName=\"!rounded-none !bg-transparent !px-6 !pb-2 !pt-6\"\n titleTextClassName=\"!text-xl !font-semibold !text-[var(--color-text)]\"\n closeButtonClassName=\"!h-10 !w-10 !rounded-none !border-0 !bg-transparent !p-0 !text-[var(--color-text)] hover:!bg-transparent hover:!text-[var(--color-text)]\"\n contentClassName=\"!rounded-none !bg-transparent !px-6 !pb-6 !pt-2\"\n >\n <div className=\"flex flex-col gap-4\">\n <SharePreviewCard target={target} url={absoluteUrl || url} />\n <div className=\"grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4\">\n <ShareDestinationButton\n label=\"Copy Link\"\n icon={<Link2 aria-hidden=\"true\" className=\"h-6 w-6\" />}\n onClick={() => void handleCopy()}\n ariaLabel=\"Copy link\"\n disabled={!absoluteUrl}\n />\n <ShareDestinationButton\n label=\"WhatsApp\"\n icon={<FaWhatsapp aria-hidden=\"true\" className=\"h-9 w-9 text-[#25D366]\" />}\n href={destinationUrls?.whatsapp}\n ariaLabel={`Share ${target.name} via WhatsApp`}\n disabled={!absoluteUrl}\n />\n <ShareDestinationButton\n label=\"Gmail\"\n icon={<SiGmail aria-hidden=\"true\" className=\"h-8 w-8 text-[#EA4335]\" />}\n href={destinationUrls?.gmail}\n ariaLabel={`Email ${target.name} with Gmail`}\n disabled={!absoluteUrl}\n />\n {canUseNativeShare && (\n <ShareDestinationButton\n label=\"More\"\n icon={<Share2 aria-hidden=\"true\" className=\"h-6 w-6\" />}\n onClick={() => void handleNativeShare()}\n ariaLabel=\"More sharing options\"\n disabled={!absoluteUrl}\n />\n )}\n </div>\n {copyStatus === \"failed\" && (\n <p role=\"alert\" className=\"text-center text-body text-[var(--color-red-500)]\">\n Could not copy the link.\n </p>\n )}\n {shareError && (\n <p role=\"alert\" className=\"text-center text-body text-[var(--color-red-500)]\">\n {shareError}\n </p>\n )}\n </div>\n </BasePopup>\n {toastId > 0 && <Toast key={toastId} message=\"Link copied\" onClose={dismissToast} />}\n </>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nexport type ShareDestinationButtonProps = {\n label: string;\n icon: ReactNode;\n href?: string;\n onClick?: () => void;\n disabled?: boolean;\n ariaLabel: string;\n};\n\nconst className =\n \"group flex min-w-0 flex-1 flex-col items-center justify-center gap-1.5 rounded-xl px-2 py-2 text-caption text-[var(--color-text)] transition-colors hover:bg-[var(--color-surface-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50\";\n\nfunction Contents({ icon, label }: Pick<ShareDestinationButtonProps, \"icon\" | \"label\">) {\n return (\n <>\n <span className=\"flex h-12 w-12 items-center justify-center rounded-full bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]\">\n {icon}\n </span>\n <span className=\"max-w-full truncate\">{label}</span>\n </>\n );\n}\n\nexport default function ShareDestinationButton({\n label,\n icon,\n href,\n onClick,\n disabled = false,\n ariaLabel,\n}: ShareDestinationButtonProps) {\n if (href) {\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" aria-label={ariaLabel} className={className}>\n <Contents icon={icon} label={label} />\n </a>\n );\n }\n\n return (\n <button type=\"button\" onClick={onClick} disabled={disabled} aria-label={ariaLabel} className={className}>\n <Contents icon={icon} label={label} />\n </button>\n );\n}\n","\"use client\";\n\nimport { Music, Music2, UserRound } from \"lucide-react\";\nimport type { GenreTreeShareTarget } from \"./share\";\n\ntype SharePreviewCardProps = {\n target: GenreTreeShareTarget;\n url: string;\n};\n\nexport default function SharePreviewCard({ target, url }: SharePreviewCardProps) {\n const Icon = { genre: Music2, artist: UserRound, song: Music }[target.kind];\n const typeLabel = { genre: \"Genre\", artist: \"Artist\", song: \"Song\" }[target.kind];\n\n return (\n <div className=\"rounded-3xl bg-[var(--color-surface-muted)] p-4\">\n <div className=\"flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg\">\n <div className=\"flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]\">\n <Icon aria-hidden=\"true\" className=\"h-10 w-10\" />\n </div>\n <div className=\"flex min-w-0 flex-1 flex-col justify-center gap-1 p-4\">\n <span className=\"text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]\">{typeLabel}</span>\n <span className=\"truncate text-base font-semibold text-[var(--color-text)]\" title={target.name}>\n {target.name}\n </span>\n <span className=\"truncate text-body text-[var(--color-primary)]\" title={url}>\n {url}\n </span>\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { Pause, Play } from \"lucide-react\";\nimport { ActionButton } from \"@behindthemusictree/ui\";\nimport {\n genreMusicCount,\n genreMusicSelectionKey,\n type GenreMusicSelection,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nimport type { PlayableGenrePlaylist } from \"./GenreInfoPanelBody\";\nimport type { GenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\nimport { RegionGlobeIcon } from \"./RegionGlobeIcon\";\nimport { TreeMarkIcon } from \"./TreeMarkIcon\";\n\ntype PlayIconKind = \"play\" | \"tree\" | \"map\" | \"tree-map\";\ntype PlayOption = { key: string; label: string; icon: PlayIconKind; selection?: GenreMusicSelection; count: number };\n\n/** The play triangle is the same on every button; the scope's glyphs (tree = canonical genres, map = regional genres) stay faint behind it so it reads first. \"All\" joins the left half of the tree and the right half of the globe at the centre. */\nfunction PlayIcon({ kind }: { kind: PlayIconKind }) {\n return (\n <span aria-hidden=\"true\" className=\"relative flex items-center justify-center w-5 h-5\">\n {kind === \"tree\" && <TreeMarkIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35\" />}\n {kind === \"map\" && <RegionGlobeIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35\" />}\n {kind === \"tree-map\" && (\n <>\n <TreeMarkIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]\" />\n <RegionGlobeIcon className=\"absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]\" />\n </>\n )}\n <Play className=\"relative w-5 h-5 fill-[var(--color-surface)]\" />\n </span>\n );\n}\n\n/** One option per way to scope a genre's playlist; a plain playlist has a single option. */\nfunction playOptions(playlist: PlayableGenrePlaylist): PlayOption[] {\n if (!(\"genreOnlyTracksCount\" in playlist)) return [{ key: \"all\", label: \"Play\", icon: \"play\", count: playlist.tracksCount }];\n const direct: PlayOption = { key: \"direct\", label: \"Genre\", icon: \"play\", selection: { coverage: \"genreOnly\" }, count: genreMusicCount(playlist, { coverage: \"genreOnly\" }) };\n const scopes = playlist.genreAndSubgenresTracksCount;\n const inclusive = (label: string, icon: PlayIconKind, subgenres: \"canonical\" | \"regional\" | \"all\"): PlayOption => {\n const selection: GenreMusicSelection = { coverage: \"genreAndSubgenres\", subgenres };\n return { key: subgenres, label, icon, selection, count: genreMusicCount(playlist, selection) };\n };\n return \"canonical\" in scopes\n ? [direct, inclusive(\"Canonical\", \"tree\", \"canonical\"), inclusive(\"Regional\", \"map\", \"regional\"), inclusive(\"All\", \"tree-map\", \"all\")]\n : [direct, inclusive(\"All\", \"map\", \"all\")];\n}\n\ntype GenrePlayActionsProps = {\n genrePlaylist: PlayableGenrePlaylist;\n playback: GenrePlaylistPlayback;\n};\n\n/** Play buttons for a genre's playlist, each with the number of playable songs it covers; an empty one stays visible but disabled. */\nexport default function GenrePlayActions({ genrePlaylist, playback }: GenrePlayActionsProps) {\n const { isPlaying, setIsPlaying } = usePlayer();\n const options = playOptions(genrePlaylist);\n return (\n <>\n {options.map((option) => {\n const isCurrent =\n playback.playing?.uuid === genrePlaylist.uuid &&\n (option.selection === undefined || playback.playing.selectionKey === \"\" || playback.playing.selectionKey === genreMusicSelectionKey(option.selection).join());\n const playing = isCurrent && isPlaying;\n return (\n <ActionButton\n key={option.key}\n icon={playing ? <Pause aria-hidden=\"true\" className=\"w-5 h-5\" /> : <PlayIcon kind={option.icon} />}\n label={playing ? \"Pause\" : option.label}\n caption={String(option.count)}\n disabled={option.count === 0}\n title={option.count === 0 ? \"No playable songs\" : undefined}\n onClick={() => {\n if (isCurrent) {\n setIsPlaying(!isPlaying);\n return;\n }\n void playback.play(genrePlaylist, option.selection);\n }}\n />\n );\n })}\n </>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { REGION_GLOBES, REGION_GLOBE_PATHS } from \"./regionGlobePaths\";\n\nconst ROTATION_INTERVAL_MS = 3000;\n\nexport function RegionGlobeIcon({ className }: { className?: string }) {\n const [index, setIndex] = useState(0);\n\n useEffect(() => {\n const reducedMotion = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n let timer: ReturnType<typeof setInterval> | undefined;\n const sync = () => {\n clearInterval(timer);\n timer = reducedMotion.matches\n ? undefined\n : setInterval(() => setIndex((i) => (i + 1) % REGION_GLOBES.length), ROTATION_INTERVAL_MS);\n };\n sync();\n reducedMotion.addEventListener(\"change\", sync);\n return () => {\n reducedMotion.removeEventListener(\"change\", sync);\n clearInterval(timer);\n };\n }, []);\n\n return (\n <svg viewBox=\"0 0 512 512\" fill=\"currentColor\" className={className} aria-hidden>\n <path data-testid=\"region-globe-path\" d={REGION_GLOBE_PATHS[REGION_GLOBES[index]]} />\n </svg>\n );\n}\n","// Globe silhouettes (512x512 viewBox, SVG Repo) as raw path data so they inherit `currentColor`.\nexport const REGION_GLOBE_PATHS = {\n africa: \"M491.879,156.348c-19.45-45.96-51.89-85.017-92.734-112.614C358.3,16.13,308.964-0.008,256.004,0 c-35.306,0-69.02,7.163-99.654,20.122c-45.961,19.45-85.017,51.89-112.614,92.734C16.13,153.701-0.008,203.036,0,255.996 c0,35.306,7.163,69.02,20.122,99.654c19.45,45.961,51.882,85.017,92.735,112.614c40.844,27.605,90.18,43.743,143.147,43.735 c35.299,0,69.012-7.163,99.648-20.121c45.96-19.45,85.017-51.882,112.614-92.735c27.604-40.844,43.742-90.18,43.734-143.147 C512,220.698,504.837,186.984,491.879,156.348z M241.412,128.135c3.914-1.382,10.421,3.07,8.843,7.272 c-2.624,6.983,6.491,10.436,9.49,14.474c2.624,3.522,7.585,14.708-3.148,12.567c-5.094-1.015-6.866,5.234-13.623,1.313 c1.672-2.382,8.382-17.825,3.312-17.583C243.202,146.327,238.367,131.188,241.412,128.135z M233.812,142.281 C231.43,142.96,235.648,141.75,233.812,142.281c8.499-2.437,8.859,11.693,4.882,14.872c-8.303,6.617-8.654-0.328-7.241-5.96 C232.086,148.71,225.009,144.804,233.812,142.281z M48.445,168.331c5.914-13.966,13.224-27.199,21.708-39.572 c3.796-0.343,6.022-2.077,11.201-6.788c4.898,5.999,9.787,11.998,14.693,17.997c1.5,1.836-3.25,4.109-0.938,6.194 c2.921,2.632,4.999,2.75,8.053-0.875c2.008,3.632,4.007,7.272,6.015,10.905c-6.03,2.484-11.014,5.296-17.52,5.171 c-10.319-0.218-15.404-1.18-23.465,5.725c3.374,5.32,7.108,1.96,11.654,0c-2.07,6.093,0.914,14.842,7.897,15.802 c-3.078,2.96-6.163,5.913-9.233,8.874c-1.413,1.359-5.233-3.586-0.921-6.616c-1.57-1.203-4.835-2.562-6.764-3.015 c-0.618,7.194-7.491,2.984-10.53,7.522c-3.312,4.937,3.132,8.022-4.078,10.085c-12.084,3.452-8.655,15.88-17.872,23.019 c-0.952,0.742-3.358,2.203-5.678,3.835C35.322,206.184,40.712,186.641,48.445,168.331z M73.246,276.415 c-0.664-0.383-1.336-0.774-2.008-1.164c-0.468-2.203,5.586-1.289,6.374-0.657C79.464,276.071,73.745,276.321,73.246,276.415z M50.687,273.158c0.961,0.328,1.804,0.171,2.539-0.477c-0.938-0.758-1.945-1.414-3.008-1.96 c-0.875-3.484,18.575,2.672,15.818,4.226c-2,1.133-19.754,1.282-18.84-0.578c0.89-1.116,2.062-1.523,3.484-1.21 C49.5,272.712,50.203,272.978,50.687,273.158z M30.846,260.792c7.421,2.101,14.67,5.077,15.826,5.842 c0.305,0.211-2.733,1.437-1.758,1.765c0.985,0.227,1.906,0.586,2.796,1.055c0.875,0.726-12.068,3.663-11.31,0.695 c0.64-0.828,1.367-1.578,2.172-2.265c-0.149,0.203-3.766-1.781-7.656-3.609C30.877,263.12,30.877,261.948,30.846,260.792z M34.893,273.915c1.336-0.274,9.084,1.78,5.686,3.507c-1.148-0.164-2.296-0.336-3.437-0.508 C34.838,276.477,34.088,275.477,34.893,273.915z M167.386,365.564c-4.898,5.21-4.71,7.397-5.366,13.959 c-0.867,8.631-1.936,25.558-11.646,26.207c-15.982,1.062-20.544,14.216-25.082,26.69c-0.718,2-1.531,3.726-2.398,5.265 c-20.926-15.364-39.134-34.228-53.678-55.764c-15.63-23.152-27.042-49.336-33.213-77.502c2.265,1.031,3.171,3.312,3.179,5.663 c0,0.023,0,0.054,0,0.086c0.141-0.187,0.258-0.382,0.43-0.562c1.555-1.952,13.935-20.379,12.92-7.843 c6.999,1.445,6.038-3.921,11.154-4.772c5.499-0.914,6.788,7.108,12.201,5.39c9.498-3.023,10.186-1.555,15.411,6.288 c5.366,8.046,18.419,4.75,25.636,9.819c5.812,4.085,6.866,8.779,7.702,15.614c0.344,2.858,11.78,3.25,14.466,3.25 c2.867,0,2.429,4.062,3.655,5.6c1,1.258,5.07,0.797,6.374,0.968c6.592,0.829,14.076,2.632,19.466,6.687 C174.776,355.253,171.729,360.932,167.386,365.564z M195.304,92.75c1.585-0.336,4.342,2.726,5.248,2.125 c3.203-2.149,2.492-2.289,7.171-2.554c1.274-0.07,20.646,1.429,15.357,6.74c-0.007,0.008-0.007,0.008-0.007,0.008 c0,0.008,0,0.008-0.008,0.008c-7.452,7.436-13.256,4.96-21.988,4.96C197.318,104.037,187.977,94.265,195.304,92.75z M415.758,398.574c-3.179,10.991-2.187,13.771-12.842,17.474c-3.343-10.388-2.257-16.716-2.257-27.448 c0-0.367,14.552-13.873,16.169-15.802C421.984,382.646,418.766,388.177,415.758,398.574z M481.068,264.502 c-2.241-2.828-4.249-6.178-6.327-8.264c-4.491-4.491-16.732-0.938-23.738-1.882c-6.179-0.828-7.726,0.218-9.905-5.586 c-1.156-3.085-5.343,0.203-8.21,0.477c-8.694,0.82-12.56-13.334-20.575-8.803c2.578,4.038,10.365,16.24,13.584,17.31 c6.514,2.172,4.96-6.835,12.74-4.522c-0.618,2.366,0.281,5.155-0.375,7.514c22.738-5.748,3.14,23.129-6.905,20.981 c-2.75-0.594-1.695,3.5-4.601,4.343c-4.452,1.304-8.905,2.601-13.365,3.898c-5.648,1.648-10.654,5.758-13.842,0.297 c-7.428-12.724-12.263-28.401-21.621-38.658c-1.616-1.773-4.421-4.444-6.452-7.373c0.078,0.234,0.148,0.484,0.234,0.718 c-1.804-1.313-4.476-1.469-6.397-2.624c-2.321,6.444,6.491,15.021,10.177,20.285c4.75,6.781,5.882,16.154,10.882,22.575 c2.148,2.765,6.022,4.139,7.974,7.076c1.657,2.484,5.156,10.655,7.82,11.725c4.077,1.64,17.302-4.468,21.808-5.64 c-2.398,5.765-7.678,25.332-13.224,27.816c-10.6,4.75-13.278,9.03-20.113,18.677c-0.539,0.75-5.554,6.256-5.617,6.007 c1.266,4.944,2.531,9.888,3.789,14.832c0.936,3.664,2.336,20.138-0.485,20.966c-13.006,3.859-13.966,7.514-14.286,20.708 c-0.133,5.429-6.46,13.091-10.506,17.739c-5.936,6.819-10.545,15.99-19.715,17.263c-8.491,1.179-16.997,2.28-25.512,3.39 c0-6.881,0.633-9.397-3.694-14.583c-5.085-6.101-5.827-7.859-6.843-15.74c-1.141-8.905-11.92-21.231-9.428-29.058 c4.906-15.381,3.523-20.887-0.562-36.728c-1.226-4.773-7.186-7.343-8.413-11.803c-0.96-3.46,1.126-11.951,1.126-15.794 c-7.382,0.616-8.663,1.046-14.389-3.632c-4.694-3.835-9.194-0.352-14.747,1.445c-4.609,1.492-11.616-0.437-16.427-0.773 c-3.867-0.274-9.585,4.093-13.1,2.96c-7.413-2.39-18.2-21.575-23.309-27.644c-4.804-5.686-1.867-19.145-2.226-26.94 c-0.484-10.373,12.74-20.262,20.184-24.98c2.047-1.297,3.109-8.397,5.898-11.1c3.953-3.835,6.499-8.123,12.045-8.42 c9.764-0.516,20.903-5.335,31.026-6.764c5.632-0.797,11.272-1.594,16.912-2.39c2.328-0.329,6.475,8.389,0.758,10.1 c3.39,6.709,14.833,4.632,15.81,7.561c1.929,5.788,9.373,4.906,15.029,5.968c-0.782-14.225,10.88-3.976,17.746-2.047 c5.202,1.452,8.679-1.695,13.842-1.703c4.288-0.008,9.326,2.07,13.537,3.008c0.007,0.054,0.023,0.094,0.038,0.148 c0.07-0.328,0.157-0.656,0.29-0.984c2.812-7.03,4.178-11.21,4.178-18.724c-4.468,0.531-18.551,4.796-22.176,2.632 c-2.164-1.289-4.25-8.014-5.436-10.248c-2.062-3.906,0.687-3.859,4.265-6.194c12.318-8.03,26.535-2.484,39.892-5.366 c-1-4.85-3.57-7.178-7.14-10.154c-5.35-4.453-4.273-5.054-3.014-12.029c-3.508,1-7.015,2-10.53,3.007 c1.296,1.531,1.336,4.132,2.632,5.639c-8.828,6.148-6.359-5.163-12.404-6.006c-5.39-0.766-6.804,8.154-9.538,11.388 c-3.906,4.64,1.672,8.303-4.562,10.6c-4.351,1.602-7.241,5.577-12.217,3.952c3.664,2.024,5.882,4.976,4.882,9.022 c-1.453-0.798-3.468-0.641-4.882-1.5c0.727,1.984,0.298,4.444,1.125,6.381c-5.984-2.695-11.928-12.521-12.974-18.802 c-0.898-5.374-14.286-12.513-18.989-16.536c-7.577,8.288,13.286,12.63,15.224,19.739c-0.141-0.531-4.022,11.662-4.319,11.842 c-5.242,3.249-4.242-7.679-5.96-9.249c-5.147-4.671-15.669-19.348-21.254-14.825c-7.671,6.218-4.616-1.062-10.818,0.875 c-5.835,1.82-3.156,7.436-6.757,8.514c-9.662,2.898-2.382,5.866-8.155,10.678c-5.717,4.765-6.616,4.75-14.029,4.601 c-14.138-0.266-16.872-3.624-15.458-17.81c1.203-11.959,14.513-7.014,24.355-6.858c3.601,0.062,2.211-9.233,0.297-11.146 c-3.32-3.312-7.819-2.375-10.279-6.89c14.505-2.593,18.176-10.045,29.705-18.051c1.852-1.282,12.811-5.327,12.725-6.499 c-0.211-3.257-2.789-15.615,4.952-14.185c7.217,1.343-3.304,12.146,2.554,12.466c3.296,0.188,12.014,4.523,12.802,3.664 c4.648-5.07,10.162-3.164,16.92-2.992c2.335,0.062,5.46-11.146,6.452-13.513c8.279,8.366,6.725-2.53,5.632-7.522 c3.101,0.117,14.599,1.96,16.552-2.25c3.586-7.71-8.764-4.898-12.224-3.945c-4.085,1.11-11.778,2.039-13.349-4.327 c-0.508-2.085,4.304-12.279,6.272-13.318c5.617-2.976,7.617-5.991,1.946-10.623c-6.327-5.187-6.358,8.061-7.084,8.897 c-6.281,7.217-22.809,10.974-9.023,22.567c-4.382,0.984-6.014,3.179-6.147,7.084c-0.266,7.225,0.266,6.733-6.827,8.046 c-6.726,1.241-7.812-10.577-9.975-16.264c-4.929,5.21-15.006,14.271-19.169,2.258c-3.827-11.084,5.757-14.342,13.224-17.739 c6.351-2.882,12.646-15.802,16.95-21.387c2.531-3.273,0.43-5.117,4.234-8.257c3.788-3.116,6.96-3.483,11.826-4.577 c4.093-0.922,7.178-5.562,11.177-5.648c5.75-0.108,11.522,0.321,17.263,0.594c7.007,0.344,1.75,3.414,5.242,4.554 c5.218,1.71,10.428,3.421,15.638,5.124c5.718,1.875,17.763,6.96,13.521,12.795c-4.562,6.264-16.325-1.461-20.715-3.812 c-3.57,6.374,3.179,5.132,6.397,8.647c0.828,0.906-1.578,4.734-0.757,5.64c1.32,1.446,4.35,2.515,6.03,3.492 c5.108,2.953,3.077-8.1,1.125-6.124c2.726-2.765,4.663-2.765,9.014,0c0.641-5.827,7.257-7.913,12.037-5.265 c0.078-2.883,0.149-5.781,0.227-8.671c16.176,13.545,30.432,29.308,42.274,46.836c24.293,35.963,38.454,79.213,38.462,125.916 C481.248,258.847,481.177,261.683,481.068,264.502z M50.687,273.158c0,0,0,0-0.008,0C51.257,273.376,51.023,273.282,50.687,273.158z M432.998,199.451c0.226,1.078-5.476-4.804-5.928-5.444c-1.914-2.696-3.812-5.39-5.726-8.093 c5.89-0.257,7.695-4.014,7.523-9.389c-11.131,0-26.02,5.89-15.435,18.153c1.469,1.696,5.991,5.242,6.406,7.405 c0.305,1.578-4.391,2.858-3.906,5.32c1.586,7.904,3.742,7.17,11.428,9.725c1.952-0.141,4.163-1.555,6.022-2.25 c-1.304-2.819-4.178-6.725-4.514-9.787C428.764,204.247,433.756,203.106,432.998,199.451z\",\n americas: \"M491.875,156.347c-19.446-45.958-51.889-85.019-92.736-112.613C358.3,16.13,308.962-0.008,255.996,0 c-35.305,0-69.016,7.168-99.65,20.124C110.381,39.571,71.321,72.006,43.725,112.86C16.122,153.692-0.016,203.03,0,255.996 c-0.008,35.313,7.16,69.016,20.125,99.658c19.438,45.958,51.881,85.018,92.728,112.613C153.692,495.87,203.03,512.008,255.996,512 c35.305,0,69.016-7.168,99.649-20.125c45.966-19.446,85.018-51.882,112.621-92.736C495.87,358.308,512,308.97,512,255.996 C512,220.691,504.832,186.988,491.875,156.347z M374.27,351.228c-8.571,14.798-1.69,35.384-12.262,48.78 c-10.947,13.514-16.513,10.221-24.295,28.328c-0.853,2.36-14.742,31.917-18.211,23.122c3.054,7.854-0.383,15.66-10.357,16.274 c-7.95,0.47-2.233,5.071-4.704,8.252c-9.863,2.17-19.965,3.708-30.274,4.521c-6.928-25.299-10.74-54.6-10.565-62.972 c0.638-32.484-6.609-19.327-23.609-43.342c-11.616-16.513-21.91-34.803-21.304-55.733c-0.088,3.74,23.329-53.086,6.426-42.25 c-20.532,13.172-24.311-14.567-44.092-17.158c-10.102-1.339-7.16-11.768-18.49-9.982c-10.174,1.594-21.735-11.904-29.277-16.991 c-4.951-3.572-13.578-51.619-20.842-50.933c-10.373,0.383,7.598,33.049,3.835,34.142c-7.742,1.451-21.313-46.093-21.057-50.008 c0.39-12.63-0.83-19.75,7.527-30.251c3.245-4.226,21.718-20.475,19.773-26.304c-3.308-10.166-1.602-22.022-6.905-28.831 c4.681-3.739,9.504-7.311,14.487-10.677c10.31-6.968,21.249-13.076,32.675-18.282c1.332-0.04,2.663-0.096,3.97-0.239 c10.206-0.997,20.627-4.959,30.992-3.388c13.666,2.008,28.488,7.893,42.88,6.769c13.251-0.933,50.638-12.949,62-3.254 c5.015,4.306-56.443,21.72-58.396,30.043c-0.997,5.422,16.002,4.944,17.469,5.079c17.087,1.403-4.241,15.452,6.252,18.481 c16.114,3.891,27.738-56.338,41.205-24.844c5.502,13.06,24.406-8.547,26.543,7.566c2.153,16.951,18.426,22.684-11.506,24.885 c-28.073,2.28-4.864,14.726-23.186,22.811c-17.525,7.718-33.552,11.107-46.46,26.966c-14.559,17.987-15.954,17.389-21.671,40.408 c-3.15,12.565-19.678-8.842-13.371-16.696c-2.185,2.694-21.544-6.1-23.466-1.587c-3.755,8.706-13.961,4.035-21.982,9.369 c-10.142,6.706-20.077,28.44-9.927,38.63c8.125,8.101,36.095-17.884,37.618-9.01c1.196,6.786-9.919,11.601-8.706,18.387 c1.746,9.823,18.872-2.815,18.864,4.816c0.008,4.895-0.805,25.355,14.272,20.236c8.125-2.774,8.93,3.046,14.009,1.826 c6.96-1.683,10.07-10.963,18.275-9.752c9.766,1.427,20.714,6.371,30.074,9.13c15.213,4.504,14.535,17.214,31.463,19.821 c16.911,2.663,10.15,18.323,8.068,27.197C329.007,322.58,399.107,310.772,374.27,351.228z M440.711,127.133 c0.686,0.981,1.403,1.954,2.066,2.95c4.01,5.916,7.71,12.064,11.138,18.378c-1.443,0.494-2.806,0.893-3.851,1.012 c-4.417,0.558-11.585-3.301-12.685-4.959C436.493,143.191,439.468,131.726,440.711,127.133z M481.223,257.232 c-1.252-0.702-2.615-1.077-4.138-0.766c-5.518,1.1-26.471,6.618-34.189,5.509c-7.726-1.108-31.981-24.262-31.981-29.779 c0-5.51,1.101-26.471,3.301-29.78c2.209-3.309,14.336-18.426,18.753-25.036c4.409-6.625,11.027-15.436,16.544-16.544 c1.715-0.343,5.375-1.012,9.824-1.834c14.032,29.374,21.902,62.231,21.91,96.994C481.247,256.411,481.223,256.809,481.223,257.232z\",\n asia: \"M491.878,156.348C472.437,110.39,439.989,71.33,399.14,43.731C358.307,16.131,308.964-0.008,256,0 c-35.304,0-69.011,7.167-99.652,20.122C110.39,39.564,71.33,72.011,43.731,112.86C16.131,153.693-0.008,203.036,0,256 c0,35.304,7.167,69.02,20.122,99.653c19.442,45.957,51.889,85.016,92.738,112.616c40.832,27.6,90.176,43.74,143.14,43.731 c35.305,0,69.02-7.166,99.653-20.122c45.957-19.442,85.017-51.889,112.617-92.738c27.6-40.832,43.74-90.176,43.731-143.14 C512,220.697,504.842,186.98,491.878,156.348z M427.814,110.348c0.774,0.915,1.53,1.856,2.294,2.789 c-1.496-0.454-2.991-0.908-4.486-1.37C426.353,111.297,427.084,110.819,427.814,110.348z M382.832,101.182 C387.142,100.754,380.446,101.434,382.832,101.182c-1.798-0.126-3.159-0.858-4.066-2.177 C384.579,95.217,388.747,100.585,382.832,101.182z M290.917,81.127c1.613,4.142-9.956,0.277-11.216-0.336 c-0.739-0.739-1.294-1.58-1.663-2.52C278.021,79.203,290.388,79.749,290.917,81.127z M258.79,75.406 c2.823,0.958,14.022-1.572,14.383,1.722c0.673,6.049-3.99,0.058-4.956,0.058c-2.622,0,1.21,2.78,1.31,2.923 c-0.656-0.957-8.461-0.857-10.107-0.462C254.656,88.352,241.675,69.592,258.79,75.406z M271.711,87.026 c-3.108,1.142-8.443,0.168-11.754,0.168C253.808,85.58,276.718,85.194,271.711,87.026z M79.236,313.19 C79.06,315.812,79.346,311.544,79.236,313.19c0.042-0.663,1.126-5.755,2.084-6.049c1.513-0.453,4.613,6.999,4.487,8.041 C85.11,321.206,78.892,318.148,79.236,313.19z M136.15,339.169c-3.252-3.983-5.192-8.461-8.284-12.528 c-0.63-0.84-11.031-6.754-9.058-7.796c4.243-2.21,39.505,18.517,37.934,21.676c-0.152,0.303-7.889-6.797-9.847-5.52 c-1.302,0.848,2.689,3.932,2.689,5.419c2.016,1.033,7.149,8.646,2.932,8.872C147.862,349.545,138.872,342.512,136.15,339.169z M154.894,340.546c0.21,1.37-3.646-1.185-3.873-1.277C151.777,337.884,154.718,339.412,154.894,340.546z M151.92,353.208 c-3.898-2.487,12.569-0.554,13.459-0.487c3.252,0.243,11.418,0.076,13.552,3.974C179.569,357.862,155.574,355.544,151.92,353.208 C154.356,354.77,150.122,352.066,151.92,353.208z M188.686,317.644c4.125-4.201,8.839,3.235,9.174,2.932 c-2.596,2.369-6.486,6.94-1.252,9.671c3.932,2.058-4.672,3.537-4.672,4.268c0,2.966-4.771,10.795-7.814,12.014 c0.177-0.067-11.913-3.419-12.972-3.722c-2.638-0.764-3.445-8.082-5.058-10.426C166.093,328.036,184.51,321.895,188.686,317.644z M167.53,281.869c1.756-1.328,3.378-1.479,4.848-0.454C173.546,287.801,165.514,282.785,167.53,281.869z M195.718,306.864 c0.009-0.017,0.017-0.025,0.034-0.034c0.067-0.059,0.101-0.084,0.092-0.076c1.05-0.857,3.806-3.302,4.898-3.546 C203.716,302.529,193.676,308.502,195.718,306.864z M201.658,294.278c-0.563-3.353-0.151-3.974,0.093-6.68 c0.428-4.713,5.915-6.772,7.007-1.092c0.193,0.975-5.721,9.88-1.218,9.317c3.612-0.454,6.301-0.622,5.134,3.932 c-1.076-0.714-7.814-4.075-8.637-3.898c-0.798,0.168-3.36,8.746-6.049,7.939C199.162,304.151,201.809,295.95,201.658,294.278z M200.734,269.073c0.084-1.328,2.042-5.125,4.176-4.688c2.461,0.513-0.731,10.141-2.487,9.032c-1.26-1.193-1.823-2.639-1.689-4.335 C200.7,269.678,200.608,271.199,200.734,269.073z M213.479,300.403c0.016-0.008,0.016-0.016,0.034-0.016 c4.797-2.42,3.452,4.218,3.965,4.452C216.831,304.546,213.101,300.613,213.479,300.403z M218.184,308.04 C217.26,307.889,219.276,308.217,218.184,308.04c1.521,0.244,2.269,3.369,2.42,4.378c0.621,4.243,0.546,2.411-2.26,3.52 c-0.765,0.294,0.084,2.747-1.672,2.865c-0.84,0.05-5.436-0.908-3.948-2.672c3.091-3.663-5.663-0.815-5.663-1.134 c0-1.227,1.386-4.075,3.184-3.697C215.504,312.384,215.58,307.62,218.184,308.04z M223.435,335.086 c-1.311-1.748-0.118-6.075,1.159-7.512c-1.016,1.142,2.706,3.058,2.882,2.26C227.081,331.632,223.661,335.388,223.435,335.086z M230.03,343.202c-0.076-0.739-6.041-0.588-6.948-0.73C221.51,342.471,229.593,338.766,230.03,343.202z M223.704,262.839 c-3.907,0.89,0.816-2.747,1.664-2.823C226.518,259.907,223.914,262.554,223.704,262.839z M222.393,355.989 c1.529,3.941-8.503,4.672-9.906,5.008c1.076-0.261,7.284-2.588,7.898-4.26C220.494,356.426,221.612,353.964,222.393,355.989z M200.557,343.369c-2.243,1.227,0.21,5.831-2.16,6.066c-3.503,0.352-1.638-8.755-0.866-11.208 c3.798-11.998,9.352,4.495,12.469-3.47c-0.252,0.647-10.847-2.655-9.091-3.201c0.025-0.008,0.051-0.008,0.076-0.017 c2.89-0.873,12.997-3.184,15.408-2.596c0.571,0.134-6.662,10.132-10.636,9.83c4.798,0.369,2.705,7.419,0.941,9.351 c-0.63,0.689,4.411,2.646,3.722,3.117C207.993,352.914,197.574,345,200.557,343.369z M206.497,356.938 c0.597,0.303-2.731,1.025-3.159,1.109c-1.377,0.47-2.688,0.412-3.932-0.176C198.465,357.115,205.691,356.535,206.497,356.938z M199.297,358.946c-0.647,0.404-1.336,0.404-2.067,0C195.256,357.744,198.348,357.938,199.297,358.946z M205.548,300.05 c0,0,0,0-0.009,0c-0.025-0.025-0.051-0.042-0.076-0.058c0.017,0.008,0.034,0.025,0.058,0.041c-0.235-0.159-2.68-1.814-0.84-2.008 C207.278,297.757,205.582,300.076,205.548,300.05z M208.783,308.284c-2.798,0-3.016-4.05-3.134-5.621 C207.748,296.421,209.429,308.284,208.783,308.284z M209.975,358.132c0.74-0.387,8.208-2.403,7.704-1.613 c-0.471,0.748-8.838,4.604-9.679,2.924C208.228,358.527,208.883,358.09,209.975,358.132z M218.839,343.202c0.008,0,0.017,0,0.017,0 c-0.026,0-0.009,0-0.026,0c-1.142,0.051-1.622-0.328-1.403-1.143c2.445-1.126,3.344,1.303,1.429,1.143 C219.318,343.244,219.091,343.226,218.839,343.202z M209.707,304.738c-0.093-0.042-0.06-0.025-0.009-0.008 c-1.294-0.512-0.109-3.394,1.084-2.118C211.177,303.041,210.454,305.016,209.707,304.738z M212.244,305.528 c-0.084,0.68-0.605,3.453-1.84,3.453c-0.218-0.74-0.218-1.479,0-2.218C210.539,305.629,211.151,305.218,212.244,305.528z M202.355,305.184L202.355,305.184c-0.58,1.168-7.78,9.838-8.839,5.184C193.542,310.486,201.884,306.142,202.355,305.184z M194.903,356.737c-1.512,0.395-2.789,1.294-4.47,0.344C188.719,356.115,194.836,356.737,194.903,356.737z M187.451,356.325 c-0.992,0-0.446-0.656,0.268-0.739C188.442,355.502,188.35,356.325,187.451,356.325z M281.365,457.809 c-5.629,13.039-11.771-7.864-10.998-7.62C277.752,452.726,286.145,446.736,281.365,457.809z M293.849,421.691 c-1.949,5.721-3.814,11.728-7.343,16.845c-4.864,7.049-8.561,3.294-15.064,3.234c-3.723-0.034-2.849,2.866-6.916,1.278 c-2.285-0.899-5.402-1.597-7.444-2.916c2.521,1.63-4.394-9.427-3.764-5.411c-0.344-2.167-2.823-1.084-4.848-1.479 c1.093-1.386,1.042-3.537,2.151-4.915c-2.747-0.067-5.091,1.135-6.814,3.277c-7.738-9.561-14.93-10.452-27.372-7.327 c-2.882,0.723-8.604,5.361-10.208,5.361c-6.537,0-8.041-0.261-12.914,3.596c-3.344,2.646-11.703,0.84-12.678-3.596 c-0.446-2.016,3.218-4.797,3.226-6.89c0.008-1.327-3.84-2.596-4.31-3.94c-0.723-2.108,1-4.596-0.781-6.343 c-0.748-0.731-4.125-3.15-4.243-4.15c-0.151-1.319,2.874-2.731,2.874-4.386c0-2.336,0-4.663,0-6.999 c0-5.284,14.291-6.46,19.962-9.057c6.629-3.025,1.764-4.906,5.881-8.427c1.236-1.05,5.529,1.008,6.822,0 c0.739-0.571-0.218-3.36,0.781-4.478c1.412-1.562,7.796-8.108,8.284-1.874c0.286,3.697-0.067,3.402,3.99,3.402 c3.268,0-0.176-1.604,1.302-2.948c2.244-2.05,5-8.645,7.898-9.511c1.697-0.513,10.183,3.268,12.914,3.277 c-0.95,2.73-1.874,5.478-2.865,8.2c4.267,2.16,12.258,8.788,17.223,5.906c2.318-1.352,3.268-13.014,3.949-15.745 c2.881,4.453,7.83,7.755,9.519,12.09c2.579,6.604,6.864,6.83,10.729,12.233c3.604,5.016,6.906,9.864,9.906,15.199 C297.757,412.423,296.564,413.717,293.849,421.691z M237.466,240.155c1.05,1.444-3.789,8.956-4.907,6.982 c-0.772-1.37-0.982-4.73-1.554-6.428c-0.109-0.319-0.319-0.958,0-0.008C230.064,237.928,236.24,238.475,237.466,240.155z M267.989,202.381c3.991-0.008,4.168,5.125,8.604,3.772c-0.866,0.26,2.478,3.621-2.16,4.486c-2.916,0.529-6.965,3.73-10.166,1.63 c0.428,0.286,0.218,0.151,0.008,0.016c1.95,1.311-3.47,2.412-3.671,0.89C260.604,213.202,270.182,202.372,267.989,202.381z M268.569,177.066c0,0.092,1.604-2.21,2.252-3.176c-0.706,2.824,6.435,16.526,4.335,17.173c-1.31,0.404-3.101-2.134-3.596-1.529 c-2.209,2.697,1.74,6.83,0.479,7.973c0.319-0.286-2.958,0.723-3.772,1.193c0.017,0.152,0.042,0.236,0.067,0.236 c-0.335,0-0.302-0.093-0.067-0.236C268.023,196.458,268.712,178.62,268.569,177.066z M291.959,363.442 c-7.687,1.613-17.484-13.88-21.886-7.05c-3.151,4.89-16.854-2.201-17.409-0.083c0.782-2.992,5.84-0.933,2.579-5.294 c-2.805-3.756-6.351-3.546-10.897-4.201c-3.251-0.47-2.352-2.453-3.772-4.268c-0.874-1.117-1.832,1.958-2.689,1.639 c-0.118-0.042-4.848-6.982-4.848-7.209c5.864-7.688,7.494,2.764,10.771,4.1c6.612,2.697,6.704-4.73,13.098-1.806 c3.251,1.487,27.7,10.418,26.877,12.493c-0.428,0.496-0.949,0.874-1.571,1.118C283.382,354.77,291.144,363.618,291.959,363.442z M239.138,239.726c0-0.009,0-0.009,0-0.017c0.907-2.848,8.679-3.907,7.301-0.756C245.725,240.592,238.088,243.12,239.138,239.726z M261.218,221.948c0.008-0.176,3.126-11.066,4.722-8.15c1.756,3.218,0.95,19.433-2.874,21.769 c-0.991-0.084-1.352-0.597-1.076-1.538c0,2.05-13.325,5.05-13.14,5.234c-2.075-2.151,1.344-3.428-3.756-2.941 c0.075,0-11.309,1.487-7.746-0.546c3.798-2.168,7.074-2.714,11.527-2.798c3.646-0.067,3.319-5.276,5.94-5.511 c1.227-0.109,0.538,3.369,2.748,1.537C260.478,226.586,260.881,225.46,261.218,221.948z M292.53,351.729 c-2,0.488-7.343-2.218-5.478-2.453c-1.646,0.201-0.588,0.067,0.017-0.009c3.285-0.412,7.612-1.697,10.217-1.966 C299.899,347.041,293.539,351.486,292.53,351.729z M299.706,347.142c-0.513-0.538-0.908-1.134-1.16-1.806 C296.354,341.832,303.705,348.604,299.706,347.142z M376.371,386.555c-0.924-0.143-1.252-0.672-0.991-1.58 c0.984-2.823,3.059,1.033,3.386,1.37C377.968,386.412,377.169,386.488,376.371,386.555z M379.958,381.53 c-0.865,0,1.924-3.042,3.588-1.395C385.26,381.824,380.295,381.446,379.958,381.53z M397.502,128.882 c-4.588-0.865-3.108-4.159-6.713-4.462c-4.226-0.353-1.932,5.016-5.713,4c-13.897-3.73-0.63,5.469-4.882,9.612 c0.428-0.412-7.335-1.093-8.712-0.622c-2.815,0.966-6.738,1.622-9.108,3.352c-3.193,2.336-6.385,4.672-9.578,6.999 c-1.68,1.236-3.822-2.016-6.15-0.932c-2.731,1.269-8.78,0.513-10.595,1.697c-1.941,1.277-3.369,7.192-4.318,9.208 c-3.756,8.007-8.108,25.087-19.727,26.222c-0.572-4.79-5.957-24.718,3.73-25.752c7.747-0.84,18.82-12.014,16.728-19.845 c-7.771,0.311-3.847,4.739-7.183,6.235c-6.084,2.722-6.94-3.168-9.074-2.286c-6.377,2.655-6.974,2.454-8.284,8.755 c-0.487,2.336-8.847,0.774-11.107,0.689c-6.436-0.227-22.358-2.588-27.138,0.605c-7.427,4.957-14.854,9.914-22.282,14.871 c3.982,7.579,14.846,2.512,17.224,10.167c1.571,5.023-5.192,14.938-8.914,18.76c-3.664,3.772-7.335,7.545-11.006,11.318 c-3.512,3.612-3.991-0.488-7.352,1.411c-5.218,2.941-5.201,11.897-12.57,12.14c3.117,4.109,3.681,7.016,4.058,11.847 c0.378,4.89-3.243,4.487-8.007,6.192c-0.143-3.016-0.588-6.04,0-9.023c0.849-4.26-4.074-0.336-3.226-4.588 c1.47-7.385-7.906-3.201-11.846-2.134c0.302-2.134-0.412-4.444,0-6.561c-4.067,2.294-8.132,4.595-12.199,6.889 c3.688,3.185,6.284,7.276,11.838,4.587c0.571,4.075-3.126,4.537-6.814,6.562c5.142,3,5.436,9.83,6.948,14.779 c1.932,6.285-2.252,8.41-6.645,13.561c-4.672,5.478-5.655,6.982-12.746,8.931c-3.932,1.092-7.864,2.176-11.796,3.26 c-2,0.554-0.319,3.428-4.117,3.428c-0.982-6.73-8.847-1.386-11.258,1.512c-3.579,4.284,3.159,7.486,6.756,10.998 c9.653,9.436-3.874,15.123-10.931,19.962c-2.563-6.772-10.234-8.67-12.208-14.106c-2.689,9.838-3.285,10.074,4.033,17.568 c5.335,5.469,6.058,9.796,8.175,16.87c-4.31-1.966-9.377-2.907-11.073-7.142c-2.076-5.167-3.621-8.048-7.47-12.267 c-3.965-4.352-4.134-17.256-6.225-23.231c-1.555,1.168-4.201,1.118-5.747,2.294c-1.16-4.436-4.217-16.913-9.687-18.694 c-4.453-1.453-14.241,4.646-17.82,7.267c-4.721,3.47-15.476,8.226-15.636,14.09c-0.268,10.234-0.538,10.998-8.897,17.677 c-8.007-11.67-12.108-21.239-14.359-34.775c-7.662,3.755-11.872-6.578-16.509-10.821c-2.151-1.957-6.16-2.151-10.461-1.966 c-0.092-2.655-0.15-5.318-0.15-7.99c0-31.145,6.301-60.728,17.694-87.672c16.123-38.135,42.504-70.936,75.649-94.922 c2.142-0.05,4.251,0.286,6.326,1.294c4.025,1.966,9.368-4.974,15.392-2.924c-2.142-8.746,18.668-9.174,13.997,0.328 c4.537-1.336,8.486-3.184,13.208-2.487c7.746,1.126,5.578,2.403,4.529,9.368c-0.042,0.261-24.189,8.838-15.812,10.014 c8.108,1.143,15.132-4.327,23.542-3.713c9.687,0.698,14.005,4.89,24.424,5.184c-4.159-9.99,12.728-2.789,17.946-1.638 c-5.78,4.748,5.738,10.158,9.696,13.452c-0.143-7.301,14.871-5.973,21.6-5.629c3.706,0.194,1.983-6.638,6.57-5.839 c6.226,1.084,12.443,2.167,18.668,3.251c5.252,0.916,8.015-0.344,13.148,2.403c3.512,1.882,1.143,6.394,5.948,5.882 c3.42-0.362,11.595-2.806,14.048-0.362c3.655,3.638,1.597,7.814,7.596,9.805c1.352-6.663,12.871-6.612,18.66-4.924 c2.68,0.79,14.972,10.544,10.41-1.311c10.871,2.21,21.734,4.411,32.606,6.621c4.26,0.866,4.352,4.192,7.956,5.848 c2.344,1.076,8.856,0.748,12.2,1.966C413.851,126.9,403.425,130.008,397.502,128.882z M406.693,134.654 c0.176-0.588,0.362-1.176,0.546-1.764c1.429-1.412,9.62-1.546,10.814,0.428C419.136,135.108,407.441,135.293,406.693,134.654z M437.107,168.185c4.974-4.864,9.897-9.754,15.081-14.425c-10.149,0.513-12.468,2.932-14.358-6.562 c-2.151,1.31-4.31,2.621-6.461,3.932c-2.638-3.923-8.838-9.552-2.874-13.778c1.782-1.252,6.008,0.487,7.898-0.656 c1.832-1.1,3.293-6.008,4.31-7.873c-5.176-1.84-5.31,2.723-9.334,2.63c-3.881-0.092-9.258-3.293-12.922-4.596 c3.377-6.99,11.485-5.906,17.013-6.939c2.521,3.318,4.982,6.687,7.326,10.158c6.41,9.494,12.09,19.508,17.022,29.943 C453.406,164.791,445.156,170.715,437.107,168.185z M453.18,278.096c-1.051,0.194-1.673-1.747-0.236-1.747 C454.381,276.349,454.381,277.878,453.18,278.096z M457.011,283.785c-0.47-0.58-0.227-0.278-0.008-0.017 c-2.243-2.739-1.663-6.209,2.403-4.352C461.498,280.356,458.43,285.499,457.011,283.785z M231.005,240.701v0.008C231.055,240.86,231.089,240.945,231.005,240.701z M287.07,349.268c-0.008,0-0.008,0.009-0.017,0.009C287.608,349.2,287.414,349.226,287.07,349.268z\",\n} as const;\n\nexport type RegionGlobe = keyof typeof REGION_GLOBE_PATHS;\n\nexport const REGION_GLOBES: readonly RegionGlobe[] = [\"africa\", \"americas\", \"asia\"];\n","// The Music Tree mark (brand `the-music-tree-mark.svg`, 551x567 viewBox, y-flipped at 0.1 scale) as raw path data so it inherits `currentColor`.\nexport const TREE_MARK_PATH =\n \"M3171 5598 c-5 -13 -5 -24 0 -26 5 -2 9 -16 9 -31 0 -25 -3 -28 -25 -23 l-25 4 0 -116 c0 -64 3 -116 8 -116 10 0 32 51 26 61 -3 5 -1 9 4 9 5 0 15 12 21 28 7 15 26 36 43 47 30 20 88 105 71 105 -4 0 -33 -21 -62 -47 l-54 -47 6 63 c4 35 7 72 7 82 0 10 9 19 23 22 16 3 13 5 -11 6 -25 1 -35 -4 -41 -21z M2893 5485 c8 -76 24 -100 71 -100 l36 0 0 53 c0 58 -15 69 -28 20 -8 -29 -10 -30 -16 -13 -15 43 -42 89 -55 93 -11 4 -13 -6 -8 -53z M2484 5438 c8 -70 49 -169 54 -131 2 12 10 27 18 33 17 15 19 84 3 129 -9 27 -16 31 -46 31 l-36 0 7 -62z M2625 5448 c-7 -22 -24 -121 -31 -179 l-6 -57 -27 11 c-15 5 -32 19 -37 31 -9 21 -88 86 -105 86 -39 0 38 -104 118 -158 17 -12 56 -59 86 -105 30 -45 67 -92 81 -104 14 -13 26 -30 26 -38 0 -13 -9 -11 -45 11 -67 39 -58 10 21 -66 67 -65 96 -110 108 -167 4 -17 13 -34 20 -36 20 -8 66 -186 75 -289 13 -161 -8 -272 -72 -365 -12 -18 -30 -33 -39 -33 -23 0 -53 33 -79 89 -25 54 -69 112 -121 162 -35 33 -38 40 -38 92 0 58 36 172 79 252 25 47 29 125 6 125 -19 0 -30 -22 -50 -100 -9 -35 -24 -78 -32 -94 l-16 -30 -19 24 -20 25 7 -58 c8 -62 0 -127 -16 -127 -19 0 -122 107 -166 172 -52 79 -68 150 -60 273 8 108 17 129 67 149 58 23 97 64 105 109 9 47 -5 49 -63 6 l-42 -30 15 35 c17 41 20 102 5 111 -18 11 -45 -4 -64 -36 -11 -19 -20 -60 -23 -110 -4 -54 -10 -79 -18 -79 -20 0 -27 28 -30 108 -2 40 -6 76 -9 79 -3 4 -6 51 -6 105 0 86 -3 101 -21 119 -27 27 -42 20 -53 -24 -7 -28 -5 -51 7 -90 9 -30 17 -76 17 -103 l0 -49 -29 51 c-29 49 -92 114 -111 114 -6 0 -10 -11 -10 -25 0 -14 5 -25 10 -25 6 0 10 -6 10 -13 0 -7 23 -44 51 -82 61 -84 59 -82 52 -57 -3 14 2 24 15 31 12 6 23 23 25 38 2 16 5 2 6 -29 1 -46 -2 -58 -14 -58 -21 0 -19 -13 10 -70 22 -44 25 -61 25 -165 l0 -116 -47 27 c-65 36 -142 118 -176 187 -15 31 -37 62 -49 68 -21 11 -21 10 -15 -41 l6 -52 -29 6 c-37 7 -39 -7 -4 -31 14 -10 53 -40 86 -68 92 -76 130 -104 163 -119 39 -19 101 -84 109 -116 10 -42 50 -88 217 -245 50 -47 94 -102 134 -167 33 -54 65 -98 71 -98 17 0 45 -79 51 -145 4 -47 0 -76 -20 -135 -14 -41 -39 -121 -56 -177 -18 -57 -35 -103 -40 -103 -4 0 -26 13 -49 30 -31 22 -50 49 -82 117 -99 209 -116 241 -185 337 -123 172 -123 173 -128 311 -5 140 -29 245 -57 245 -12 0 -20 -11 -24 -31 -9 -46 -7 -108 3 -127 14 -26 25 -162 14 -162 -20 0 -160 99 -192 135 -19 22 -42 58 -52 80 -10 23 -27 52 -37 66 -10 13 -26 38 -34 54 -9 17 -23 45 -33 64 -15 29 -16 40 -6 80 31 116 34 139 27 205 -7 57 -11 69 -28 74 -14 3 -32 30 -54 79 -21 46 -39 73 -47 70 -13 -5 -14 -15 -3 -65 l8 -33 -49 25 c-61 31 -93 40 -93 27 0 -13 43 -41 122 -79 47 -22 72 -41 83 -61 19 -38 19 -51 0 -51 -12 0 -15 -15 -16 -72 -1 -79 -12 -134 -22 -108 -3 8 -10 48 -16 89 -14 89 -25 111 -54 111 -38 0 -50 -15 -45 -54 4 -40 2 -42 -26 -21 -29 22 -36 19 -36 -20 0 -39 39 -85 125 -145 38 -27 62 -56 99 -120 45 -79 82 -177 70 -189 -2 -3 -42 3 -87 13 -45 10 -99 21 -119 26 -47 9 -103 51 -125 93 -24 44 -83 203 -94 252 -5 25 -4 59 3 91 14 68 3 140 -23 155 -12 6 -23 8 -27 5 -14 -15 -13 -115 2 -159 39 -116 0 -116 -70 1 -22 36 -31 42 -59 42 -20 0 -35 6 -39 15 -6 16 -56 21 -56 6 0 -5 23 -25 51 -44 53 -36 158 -156 188 -216 10 -20 26 -60 36 -88 11 -29 25 -53 32 -53 8 0 13 -12 13 -30 0 -26 -4 -30 -27 -31 l-28 -1 25 -7 c26 -8 177 -87 196 -102 5 -4 50 -18 100 -29 122 -29 277 -78 300 -95 10 -8 26 -15 34 -15 35 0 160 -166 160 -212 0 -22 -32 -24 -50 -4 -11 14 -100 46 -165 61 -16 3 -68 25 -115 48 -102 49 -163 56 -168 19 -9 -62 58 -104 178 -112 63 -5 103 -14 155 -37 39 -16 91 -38 117 -47 26 -9 74 -35 106 -56 52 -33 65 -48 96 -112 20 -40 39 -95 43 -122 6 -47 6 -48 -18 -41 -33 10 -69 33 -69 45 0 6 -10 10 -23 10 -13 0 -27 4 -32 9 -6 5 -27 14 -47 20 -20 7 -53 23 -73 37 -43 29 -45 29 -45 7 0 -26 80 -96 145 -127 119 -56 274 -185 311 -259 55 -107 104 -410 104 -640 0 -162 -22 -325 -45 -333 -25 -10 -72 25 -168 123 -129 131 -140 148 -182 274 -20 60 -50 142 -66 181 -16 39 -45 131 -65 202 -24 93 -55 173 -104 274 -77 158 -78 166 -32 256 31 64 27 129 -12 181 -31 40 -39 42 -65 18 -51 -49 -55 -120 -11 -208 37 -74 37 -85 3 -85 -36 0 -94 65 -137 154 -18 39 -37 80 -40 92 -3 11 -14 29 -24 40 -10 10 -28 35 -42 54 -13 19 -40 55 -61 80 -20 25 -41 63 -47 85 -6 22 -16 62 -23 89 -20 81 -95 147 -113 100 -18 -47 -6 -92 39 -147 25 -31 45 -61 45 -67 0 -15 -42 -3 -116 31 -94 44 -156 124 -184 235 -9 36 -13 41 -38 40 -39 -2 -144 113 -186 205 -31 66 -33 68 -53 54 -11 -8 -24 -11 -27 -7 -4 4 11 -24 33 -62 39 -67 43 -86 18 -86 -8 0 -8 3 1 9 11 6 9 9 -7 14 -11 3 -25 -1 -31 -7 -7 -10 0 -16 29 -24 39 -12 203 -147 215 -178 13 -34 4 -35 -48 -6 -64 37 -126 51 -126 30 0 -26 55 -67 125 -92 46 -16 80 -36 100 -58 l29 -33 -54 -3 c-79 -5 -203 14 -249 38 -47 24 -70 54 -105 140 -43 105 -115 163 -103 83 3 -21 9 -47 13 -57 4 -11 -15 4 -42 32 -62 64 -84 67 -84 14 0 -41 24 -76 61 -87 16 -6 18 -9 8 -15 -23 -15 15 -45 117 -91 52 -24 93 -48 91 -54 -10 -28 -150 -28 -190 0 -21 15 -47 5 -47 -17 0 -5 -10 -19 -22 -29 -23 -20 -23 -20 112 -14 174 8 208 8 430 0 l185 -7 84 -41 c115 -57 180 -118 225 -212 20 -41 36 -77 36 -80 0 -14 89 -126 150 -190 74 -78 120 -144 120 -175 0 -30 10 -33 -201 52 -94 38 -131 71 -218 195 -27 37 -59 77 -71 88 l-23 20 7 -40 c4 -22 12 -44 17 -49 13 -14 11 -26 -4 -26 -7 0 -29 21 -48 48 -33 45 -34 51 -39 159 -4 89 -9 116 -22 130 -17 16 -18 16 -18 0 0 -9 -7 -17 -16 -17 -14 0 -16 -9 -11 -62 3 -35 8 -74 12 -88 l7 -25 -25 27 c-41 44 -127 118 -137 118 -18 0 -10 -57 12 -85 18 -24 20 -32 10 -57 -10 -28 -9 -30 22 -43 18 -8 54 -19 79 -26 36 -9 60 -24 99 -66 80 -83 80 -83 1 -83 -80 0 -176 21 -236 51 -107 54 -234 169 -252 228 -4 14 -12 29 -17 35 -5 6 -18 25 -28 43 -24 40 -90 64 -116 42 -22 -18 -13 -84 17 -116 13 -13 42 -32 64 -42 22 -10 74 -53 115 -96 l75 -77 -75 5 c-135 8 -243 76 -336 207 -31 44 -65 87 -77 95 -37 26 -34 -9 7 -88 20 -39 34 -72 31 -75 -2 -2 -26 11 -52 31 -90 65 -143 83 -143 49 0 -32 71 -88 150 -117 41 -15 113 -47 159 -71 46 -24 99 -46 118 -50 18 -3 33 -12 33 -18 0 -12 -111 -46 -149 -46 -12 0 -29 -8 -39 -17 -10 -10 -27 -19 -37 -19 -11 -1 -45 -9 -75 -17 -58 -16 -110 -62 -110 -97 0 -39 116 -45 167 -9 11 8 34 31 52 51 28 32 50 43 144 74 145 47 222 48 404 5 70 -17 177 -38 237 -47 128 -19 202 -43 250 -79 18 -14 73 -42 122 -61 164 -66 208 -112 243 -251 36 -141 27 -167 -44 -123 -19 12 -63 23 -111 28 -117 13 -134 25 -275 193 -63 74 -193 151 -266 157 -29 2 -66 -1 -81 -7 -24 -10 -37 -9 -80 8 -66 26 -70 9 -11 -44 72 -65 119 -80 239 -78 60 1 109 -2 117 -8 6 -6 26 -35 42 -64 17 -30 46 -64 64 -77 19 -13 49 -40 67 -61 l34 -39 -79 3 c-57 3 -80 0 -83 -9 -3 -10 -7 -10 -18 -1 -8 6 -11 15 -8 20 3 5 0 9 -5 9 -16 0 -13 -16 6 -36 36 -36 78 -44 227 -44 119 0 152 -3 188 -19 56 -24 95 -64 125 -126 13 -27 35 -68 48 -90 14 -22 25 -53 25 -69 l0 -29 -107 5 c-131 6 -193 28 -290 100 -37 28 -82 56 -98 63 -75 32 -176 123 -277 247 -34 42 -122 98 -134 85 -5 -5 103 -138 184 -226 52 -57 46 -61 -49 -31 -87 28 -173 85 -325 214 -144 123 -189 151 -254 159 -25 2 -39 3 -32 0 6 -3 12 -16 12 -29 0 -17 -4 -23 -12 -19 -7 4 -1 -5 15 -19 15 -14 46 -30 70 -36 23 -6 60 -17 82 -25 l40 -13 -52 -1 c-49 -1 -53 -3 -53 -25 0 -28 28 -36 122 -36 54 0 62 -3 91 -32 l32 -33 -52 -3 c-88 -5 -75 -26 39 -62 130 -41 178 -63 206 -93 l22 -24 -20 -18 c-12 -11 -41 -20 -74 -23 -48 -4 -60 0 -116 32 -118 69 -241 96 -279 62 -13 -12 -40 -16 -104 -16 -48 0 -95 4 -105 9 -9 5 -34 16 -55 25 -20 9 -76 53 -122 97 -47 45 -88 79 -91 76 -12 -12 6 -54 41 -100 l36 -47 -74 0 c-88 0 -112 15 -78 49 26 26 21 39 -34 84 -87 73 -132 32 -50 -45 25 -23 45 -46 45 -50 0 -4 -21 2 -46 12 -45 20 -114 27 -114 12 0 -4 16 -22 35 -40 39 -38 78 -47 255 -61 164 -14 178 -17 172 -47 -2 -13 -2 -30 2 -39 5 -13 9 -13 40 2 19 9 33 20 30 25 -4 5 4 4 15 -4 21 -13 20 -15 -44 -74 -36 -33 -65 -66 -65 -72 0 -21 68 15 142 74 38 30 84 62 103 70 73 30 203 11 312 -46 32 -17 82 -33 111 -37 l53 -6 -28 -30 c-15 -16 -44 -40 -63 -52 -63 -42 -100 -82 -100 -111 0 -25 2 -26 37 -21 28 5 47 17 73 49 65 78 175 183 224 216 34 22 61 32 88 32 43 0 122 -36 152 -69 10 -11 39 -32 62 -46 43 -25 53 -46 36 -72 -11 -17 -200 -86 -232 -85 -28 1 -122 -47 -127 -65 -3 -8 14 -13 54 -15 l58 -3 -65 -44 c-36 -25 -68 -49 -71 -53 -11 -17 -115 -10 -188 12 -105 32 -112 11 -14 -39 l56 -28 -40 -6 c-52 -9 -96 0 -154 29 -31 15 -50 19 -60 13 -15 -10 -16 -10 44 -47 20 -13 37 -27 37 -31 0 -15 -144 -71 -205 -81 -33 -5 -85 -10 -116 -10 -32 0 -63 -6 -75 -14 -18 -13 -15 -15 34 -22 l53 -7 -31 -18 c-18 -12 -30 -27 -30 -40 0 -21 4 -21 61 -16 50 4 75 14 145 57 46 28 112 63 146 77 62 24 191 62 215 63 22 0 -47 -103 -107 -161 -42 -41 -60 -66 -65 -92 -10 -49 0 -60 47 -54 65 9 99 53 124 160 20 83 49 133 94 163 22 15 40 30 40 34 0 4 8 10 18 13 9 3 31 15 49 27 31 21 31 21 26 0 -3 -11 -21 -37 -40 -58 -43 -45 -72 -106 -73 -150 0 -39 18 -49 56 -30 38 18 63 64 75 137 13 82 40 142 89 194 22 24 40 49 40 54 0 6 24 21 53 34 49 22 63 23 237 20 193 -2 278 -14 348 -50 21 -11 44 -27 52 -36 7 -9 32 -27 55 -41 49 -28 138 -147 184 -243 16 -35 42 -114 57 -175 35 -147 31 -268 -14 -436 -17 -63 -37 -166 -45 -227 -12 -94 -21 -127 -54 -195 -22 -46 -52 -94 -67 -108 -15 -14 -46 -44 -68 -67 -23 -24 -47 -43 -53 -43 -7 0 -25 -12 -41 -26 -129 -121 -526 -267 -721 -268 -104 0 -109 -15 -19 -57 75 -35 67 -35 221 -10 125 21 235 27 235 13 0 -16 -66 -72 -85 -72 -24 0 -85 -36 -85 -49 0 -14 12 -19 58 -27 35 -5 42 -4 42 10 0 9 5 17 10 17 28 4 74 20 80 29 9 14 226 119 288 139 63 21 215 43 239 34 32 -12 12 -50 -52 -102 -36 -28 -73 -55 -83 -58 -17 -7 -66 -39 -92 -60 -8 -7 -38 -32 -67 -57 l-52 -45 42 -6 c36 -6 54 -1 122 33 44 22 120 56 169 76 112 45 222 107 289 164 46 40 84 62 107 62 18 0 130 -83 130 -96 0 -8 4 -14 10 -14 5 0 39 -26 75 -59 36 -32 96 -76 132 -97 36 -21 68 -46 71 -56 5 -19 21 -22 59 -12 18 5 20 9 10 19 -7 7 -69 71 -139 143 -147 149 -161 179 -80 168 136 -19 195 -39 378 -128 78 -37 147 -68 152 -68 6 0 15 -7 20 -16 8 -14 14 -15 46 -4 l38 12 -104 57 c-125 69 -148 84 -148 93 0 16 94 7 223 -22 74 -17 146 -30 160 -30 14 0 29 -4 32 -10 7 -11 54 6 115 43 l40 24 -38 1 c-22 1 -68 11 -103 21 -35 11 -107 30 -159 41 -131 31 -295 99 -406 171 -235 153 -355 366 -357 634 -1 211 65 343 285 568 117 119 206 167 368 198 153 29 267 59 328 86 80 35 166 44 264 27 148 -26 167 -38 251 -169 71 -110 136 -165 196 -165 26 0 31 4 31 23 -1 32 -28 62 -87 91 -39 20 -66 45 -118 112 -95 123 -95 135 -5 92 25 -12 77 -31 116 -43 56 -17 76 -19 97 -10 27 11 26 11 -25 29 -113 39 -138 49 -138 57 0 14 91 55 153 68 33 7 75 10 95 7 27 -4 31 -3 17 4 -19 8 -19 9 3 9 12 1 22 7 22 15 0 10 7 12 22 8 12 -3 17 -7 10 -10 -6 -2 -12 -10 -12 -18 0 -8 -6 -14 -12 -15 -27 -2 39 -17 80 -18 29 -1 42 3 42 13 0 20 -19 32 -67 45 -49 13 -53 22 -20 44 49 32 128 39 235 21 56 -9 112 -14 126 -10 26 6 96 69 96 86 0 6 -32 10 -77 10 -84 0 -126 -7 -118 -20 9 -14 -17 -24 -67 -24 -34 -1 -48 3 -48 13 0 8 -7 11 -20 8 -17 -4 -18 -2 -9 14 5 11 14 17 20 14 5 -4 9 0 9 8 0 8 16 35 35 60 35 45 35 46 14 57 -18 10 -23 8 -37 -12 -67 -95 -162 -167 -297 -225 -55 -23 -99 -47 -98 -53 2 -5 -6 -10 -18 -10 -27 0 -23 8 31 71 100 117 116 131 161 155 80 40 80 70 1 41 l-47 -18 36 38 c47 49 59 73 59 120 0 67 -24 80 -82 46 -49 -29 -76 -85 -89 -183 -10 -81 -9 -80 -89 -174 -20 -22 -43 -53 -53 -68 -28 -45 -89 -61 -217 -56 -70 2 -114 8 -118 15 -4 6 -28 13 -54 15 l-46 3 53 71 c51 68 100 104 140 104 50 0 125 73 125 122 0 30 0 31 -45 26 -28 -4 -59 -16 -82 -34 -30 -23 -35 -24 -28 -8 22 51 37 105 31 111 -13 13 -47 -34 -105 -146 -72 -138 -171 -248 -261 -292 -62 -30 -164 -44 -242 -34 -48 7 -50 8 -45 34 14 70 51 144 95 190 42 43 56 51 127 69 44 12 98 24 120 27 99 15 155 57 155 117 l0 31 -51 -5 c-40 -4 -58 -12 -87 -40 -56 -52 -66 -58 -131 -78 l-60 -18 10 27 c6 14 36 62 68 106 70 96 91 136 91 170 0 41 -18 29 -50 -35 -30 -59 -31 -60 -74 -60 -56 0 -71 -18 -101 -115 -23 -75 -43 -114 -72 -145 -8 -8 -41 -61 -73 -117 -35 -59 -75 -113 -95 -128 -37 -29 -177 -85 -210 -85 -35 0 -222 -134 -282 -202 -31 -35 -64 -64 -72 -66 -22 -4 -68 116 -88 223 -20 113 -5 256 37 340 37 76 124 182 195 238 140 110 221 137 416 137 136 0 171 6 186 28 9 15 2 17 -76 18 -47 0 -127 4 -178 9 -167 15 -274 -28 -423 -170 -72 -68 -114 -95 -128 -81 -12 12 17 138 44 194 64 132 229 243 439 298 182 46 319 21 425 -80 68 -65 144 -115 202 -135 119 -41 155 -32 72 17 -88 52 -224 144 -224 152 0 14 51 20 210 22 115 2 160 0 175 -10 19 -12 18 -13 -8 -9 -36 6 -45 -9 -11 -17 56 -15 117 -51 183 -110 66 -59 119 -86 169 -86 54 0 31 59 -35 90 -167 77 -176 82 -158 93 25 13 138 -8 201 -37 27 -13 67 -43 89 -66 50 -53 84 -70 134 -70 37 0 71 19 71 40 0 24 -62 57 -129 70 -40 7 -74 17 -77 22 -3 4 24 8 60 8 36 0 68 -4 71 -10 3 -5 26 -10 51 -10 50 0 57 15 23 46 -24 21 -113 25 -226 10 -50 -7 -65 -6 -77 7 -19 18 -100 37 -160 37 -74 0 -136 12 -136 26 0 17 11 23 53 28 32 4 83 29 97 47 8 10 71 40 99 47 28 7 159 8 309 1 50 -2 92 -1 92 4 0 4 14 7 30 7 23 0 30 -4 30 -20 0 -15 -7 -20 -25 -20 -42 0 -28 -17 30 -39 75 -28 103 -27 117 4 8 18 19 25 38 25 34 0 47 35 23 62 -24 27 -70 31 -190 18 -101 -11 -112 -10 -173 10 -36 12 -104 24 -152 27 -49 3 -88 9 -88 13 0 8 35 26 66 35 12 3 37 21 55 40 19 20 67 58 106 86 57 39 86 52 134 60 71 11 170 58 193 91 34 49 10 51 -66 5 -52 -31 -154 -65 -165 -54 -11 12 9 25 67 47 33 12 60 26 60 30 0 5 15 17 34 28 31 18 67 84 53 98 -15 15 -69 -17 -124 -75 -35 -36 -63 -63 -63 -58 0 4 14 31 30 60 43 77 39 180 -7 151 -39 -24 -56 -62 -63 -141 -7 -87 -27 -127 -98 -200 -50 -52 -120 -103 -139 -103 -8 0 -22 -8 -31 -17 -31 -31 -26 11 12 94 33 74 61 171 53 180 -3 2 -17 1 -32 -3 -38 -10 -65 -74 -75 -185 -9 -97 -31 -147 -79 -176 -31 -20 -81 -71 -81 -83 0 -5 -24 -16 -52 -26 -29 -9 -58 -24 -64 -32 -7 -9 -33 -17 -70 -19 l-59 -4 55 48 c120 105 133 126 66 103 -19 -6 -58 -36 -88 -66 -29 -30 -72 -64 -96 -76 -41 -19 -50 -20 -163 -9 -168 16 -237 52 -196 103 21 27 121 88 143 88 60 0 183 34 234 65 30 18 74 36 97 40 85 14 180 99 131 118 -16 5 -19 13 -14 33 7 25 5 25 -26 19 -52 -11 -83 -31 -122 -76 -54 -63 -94 -86 -197 -109 -52 -12 -102 -24 -111 -26 -28 -8 -22 22 10 44 15 11 35 34 45 51 16 27 16 31 2 31 -8 0 -18 -7 -22 -16 -8 -23 -23 2 -23 40 0 23 -3 27 -12 18 -14 -14 -42 -16 -33 -2 3 6 4 10 1 10 -9 0 -37 -61 -62 -133 -29 -84 -85 -162 -137 -189 -24 -12 -67 -21 -110 -24 -40 -2 -100 -6 -134 -9 l-62 -4 36 72 c20 39 48 84 62 98 29 29 86 122 96 157 9 32 -20 29 -42 -5 -17 -27 -128 -174 -222 -297 -45 -58 -101 -96 -141 -96 -48 0 -9 184 59 284 41 59 113 107 234 156 51 20 141 67 198 102 57 36 118 72 134 80 40 21 155 46 240 53 48 5 82 14 113 32 58 34 150 44 258 28 41 -6 57 -4 75 9 17 12 46 16 111 16 88 0 116 12 57 24 -17 3 -48 6 -69 6 -21 0 -43 6 -49 14 -14 17 -8 22 40 31 30 5 36 10 32 26 -4 13 0 19 12 19 23 0 95 44 129 79 34 35 30 67 -6 55 -13 -4 -31 -7 -41 -6 -11 0 -38 -25 -68 -64 -28 -35 -53 -64 -55 -64 -2 0 7 22 21 50 14 27 25 60 25 74 0 14 5 37 11 53 7 19 7 29 0 31 -6 2 -11 17 -11 33 0 16 -4 29 -10 29 -5 0 -10 -19 -10 -42 0 -50 -37 -158 -74 -222 -28 -48 -90 -86 -141 -86 l-29 0 36 38 c20 20 43 52 52 70 16 31 16 32 -5 32 -25 0 -94 -47 -109 -75 -19 -35 -161 -104 -245 -120 -42 -8 -85 -15 -96 -15 -18 0 -18 1 -2 35 9 19 20 35 25 35 4 0 8 6 8 13 0 7 13 34 30 60 30 48 75 77 182 117 58 21 112 66 176 146 26 31 57 57 84 69 124 52 167 75 177 93 17 33 -14 35 -71 6 -29 -14 -69 -32 -89 -39 l-38 -14 20 51 c11 28 24 59 29 68 10 19 -20 60 -45 60 -18 0 -21 46 -4 52 6 2 14 26 16 53 4 43 2 52 -16 63 -20 11 -21 10 -21 -25 -1 -209 -5 -248 -32 -305 -34 -73 -116 -188 -133 -188 -8 0 -20 -6 -27 -13 -7 -7 -29 -18 -48 -24 -19 -6 -52 -18 -72 -27 -34 -15 -38 -15 -38 -1 0 35 32 73 89 109 60 37 77 51 45 39 -14 -5 -14 -3 -3 14 7 13 9 28 4 39 -5 11 -7 24 -6 29 1 6 -19 -11 -44 -37 -25 -26 -45 -44 -45 -40 0 4 18 34 40 67 30 45 40 69 40 100 0 53 -11 67 -46 63 -22 -2 -34 -13 -53 -47 -14 -25 -26 -40 -29 -33 -2 7 -10 12 -17 12 -10 0 -14 -33 -17 -142 l-4 -143 -63 -127 c-39 -81 -74 -137 -94 -154 -51 -43 -167 -87 -167 -63 0 6 26 38 58 72 32 34 66 73 75 87 18 26 23 100 8 100 -5 0 -22 -19 -38 -42 -15 -23 -52 -60 -81 -82 -31 -25 -61 -59 -74 -85 -37 -75 -125 -156 -220 -201 -46 -22 -101 -43 -121 -47 -32 -5 -37 -3 -37 13 0 36 50 229 70 269 10 23 38 95 61 160 39 116 84 211 117 248 12 13 13 20 4 29 -9 9 -21 5 -49 -18 -58 -46 -166 -272 -249 -519 -37 -110 -73 -207 -80 -216 -8 -8 -14 -21 -14 -28 0 -8 -19 -54 -41 -105 -23 -50 -61 -146 -84 -212 -49 -144 -77 -193 -152 -274 -71 -77 -89 -77 -115 2 -11 33 -27 59 -36 62 -19 6 -21 27 -23 201 -2 197 49 394 151 580 33 61 72 135 86 165 118 253 140 288 273 462 87 112 121 167 121 195 0 37 -25 27 -75 -29 -42 -48 -45 -50 -38 -23 13 50 9 145 -8 156 -19 12 -30 7 -50 -22 -23 -33 -15 -116 12 -124 28 -9 35 -49 12 -73 -10 -11 -36 -45 -58 -76 -22 -31 -44 -56 -48 -56 -12 0 -3 78 17 160 8 36 15 84 16 107 0 23 4 44 9 47 4 3 11 37 14 75 3 39 14 86 26 109 26 50 80 97 94 83 16 -16 59 -13 85 5 30 21 52 66 52 109 0 33 -2 35 -32 35 -59 0 -78 -12 -118 -69 -21 -31 -55 -74 -74 -96 l-35 -40 -1 41 c0 23 7 60 15 83 15 43 92 151 124 173 20 14 55 77 48 85 -3 2 -8 -5 -12 -16 -7 -24 -35 -17 -35 9 0 23 -13 32 -35 24 -9 -4 -12 -9 -7 -13 17 -10 2 -62 -16 -59 -11 2 -30 -24 -61 -87 -34 -68 -46 -84 -49 -67 -2 12 -8 22 -13 22 -5 0 -9 -10 -9 -22 -1 -23 -1 -23 -16 -3 -9 11 -24 37 -34 58 -11 24 -20 34 -23 25 -3 -7 -6 25 -6 72 -1 105 -21 98 -26 -10 -3 -43 -9 -76 -16 -81 -10 -6 -10 -11 0 -23 14 -16 3 -22 -15 -8 -5 4 2 -2 15 -13 51 -41 78 -76 96 -128 26 -70 25 -187 -3 -292 -13 -49 -21 -109 -20 -155 0 -104 -54 -310 -81 -310 -6 0 -11 3 -11 8 -1 44 -24 191 -41 259 l-22 85 27 108 c30 123 34 211 10 231 -20 16 -40 5 -72 -42 -21 -30 -23 -42 -18 -97 3 -36 1 -60 -4 -57 -17 11 -34 81 -34 150 -1 64 2 76 39 140 22 39 45 84 52 100 17 43 16 92 -2 98 -17 7 -17 8 -44 -73 -12 -36 -34 -87 -50 -113 -33 -56 -41 -48 -41 39 0 41 -4 54 -15 54 -11 0 -15 -18 -17 -80 -2 -45 -7 -80 -13 -80 -5 0 -10 4 -10 8 0 5 -8 16 -18 26 -58 58 -70 132 -53 314 7 69 6 92 -3 92 -6 0 -13 -6 -16 -12z m321 -503 c3 -20 4 -39 0 -42 -3 -4 -6 6 -6 20 0 17 -5 27 -15 27 -16 0 -20 12 -8 23 14 14 22 6 29 -28z m-1006 -80 c0 -8 -9 -15 -19 -15 -29 0 -35 18 -9 23 13 2 24 5 26 6 1 0 2 -6 2 -14z m327 -27 c-3 -7 -5 -2 -5 12 0 14 2 19 5 13 2 -7 2 -19 0 -25z m-462 -358 c3 -5 1 -10 -4 -10 -6 0 -11 5 -11 10 0 6 2 10 4 10 3 0 8 -4 11 -10z m-835 -40 c-6 -11 -15 -20 -19 -20 -5 0 -7 9 -4 20 3 11 12 20 20 20 11 0 11 -4 3 -20z m864 -25 c3 -9 0 -15 -9 -15 -9 0 -15 -10 -16 -27 0 -27 -1 -27 -13 7 -10 25 -10 37 -2 42 18 12 33 9 40 -7z m-892 -863 c38 2 68 0 68 -4 0 -5 -33 -8 -73 -8 -49 0 -80 -5 -95 -16 -21 -14 -22 -14 -22 5 0 14 -6 21 -20 21 -11 0 -20 2 -20 4 0 2 -3 12 -6 21 -6 13 1 13 47 -5 40 -16 70 -21 121 -18z m3218 -91 c0 -10 -7 -21 -15 -25 -11 -4 -15 1 -15 19 0 16 6 25 15 25 8 0 15 -9 15 -19z m-3479 -32 c-14 -5 -30 -14 -37 -20 -8 -7 -13 -3 -17 11 -5 18 0 20 36 19 38 0 40 -1 18 -10z m3359 -572 c0 -7 -7 -22 -15 -33 -13 -17 -14 -16 -4 14 11 33 19 41 19 19z m-3345 -198 c7 -22 -7 -39 -33 -39 -10 0 -10 4 0 20 11 17 10 22 -2 30 -12 8 -11 10 7 10 13 0 24 -8 28 -21z m445 -37 c0 -23 -35 -8 -38 16 -3 21 -2 22 17 10 12 -7 21 -19 21 -26z m-310 -647 c-28 -30 -60 -33 -60 -7 0 26 9 32 48 32 l35 0 -23 -25z M3684 5414 c-14 -21 -16 -41 -10 -124 4 -62 2 -100 -3 -100 -9 0 -17 26 -25 84 -1 11 -8 22 -14 24 -9 3 -12 -27 -12 -105 0 -69 -6 -130 -16 -164 -24 -86 -24 -85 -33 -70 -6 9 -10 3 -14 -17 -4 -20 -23 -43 -59 -72 -29 -23 -54 -46 -54 -51 -1 -5 -3 -39 -4 -76 -1 -46 -4 -60 -9 -43 -6 21 -9 15 -20 -35 -16 -74 -29 -99 -97 -197 -35 -49 -54 -86 -54 -105 0 -31 59 -200 60 -171 0 9 6 21 14 25 13 7 13 16 0 68 -17 72 -12 78 75 93 106 19 127 33 145 95 20 70 65 111 186 172 83 42 89 47 75 62 -9 8 -14 23 -11 32 5 14 5 14 -6 1 -7 -8 -41 -25 -75 -37 -54 -19 -61 -19 -56 -5 10 26 43 72 91 126 46 53 77 104 68 114 -6 6 -95 -81 -143 -141 l-30 -38 -7 80 c-4 45 -5 89 -1 98 3 10 31 34 63 53 61 37 147 112 164 144 21 38 -53 8 -126 -52 -98 -80 -100 -81 -92 -46 12 47 54 133 81 166 14 16 25 42 25 56 l-1 27 -25 -30 -26 -30 6 53 c3 28 9 74 12 100 5 40 3 50 -10 55 -10 4 -22 -2 -32 -19z m-79 -654 c0 -125 0 -126 -33 -176 -22 -36 -56 -67 -109 -103 -42 -28 -82 -51 -90 -51 -20 0 -16 22 11 59 13 18 30 46 36 62 7 16 16 29 20 29 5 0 13 33 20 73 16 102 29 149 40 142 6 -4 10 -2 10 3 0 5 13 25 30 43 16 19 30 38 30 42 0 5 8 7 18 5 15 -3 17 -17 17 -128z M2287 5348 c-10 -10 -22 -16 -27 -13 -5 3 -8 -3 -8 -12 1 -10 -2 -37 -6 -59 -6 -32 -4 -43 7 -47 23 -9 67 61 67 105 0 44 -9 51 -33 26z M1853 5256 c4 -22 11 -42 17 -46 7 -4 14 -26 17 -49 3 -22 10 -41 15 -41 5 0 7 12 4 28 -3 15 -8 46 -11 69 -4 23 -16 49 -27 60 -21 18 -21 18 -15 -21z M1780 5267 c0 -47 15 -79 42 -93 l30 -16 -7 34 c-4 18 -12 44 -19 58 -12 28 -46 40 -46 17z M1960 5120 c0 -21 30 -70 49 -80 27 -14 31 -13 31 10 0 11 5 20 10 20 6 0 8 -11 4 -25 -6 -23 -4 -25 30 -25 20 0 36 4 36 8 0 18 -68 72 -109 87 -52 18 -51 18 -51 5z M4127 5076 c-4 -10 -7 -45 -7 -79 0 -42 -6 -70 -18 -88 -56 -85 -73 -107 -106 -138 -20 -19 -36 -39 -36 -43 0 -18 34 -6 62 23 29 28 34 30 84 24 41 -6 59 -3 83 11 37 22 44 37 28 59 -16 21 -72 22 -95 2 -21 -19 -32 -22 -32 -7 0 5 38 35 84 66 77 51 106 84 106 119 0 26 -43 16 -77 -17 l-33 -32 0 47 c0 34 -4 47 -14 47 -8 0 -16 5 -18 12 -3 7 -7 5 -11 -6z M1049 5043 c-8 -10 -9 -14 -2 -10 7 5 28 -18 57 -63 48 -74 62 -86 52 -45 -4 15 -2 25 4 25 15 0 -17 72 -41 93 -27 22 -53 22 -70 0z M3400 4964 c-14 -37 -12 -60 6 -75 14 -11 18 -10 30 6 19 26 18 81 -2 89 -23 9 -24 8 -34 -20z M3910 4933 c-29 -20 -40 -33 -40 -50 0 -33 63 6 75 45 8 26 -2 28 -35 5z M3401 4844 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z M4532 4829 c-8 -12 -9 -18 -3 -14 7 4 11 -8 12 -32 1 -21 4 -51 8 -68 6 -26 8 -22 13 29 5 39 3 67 -5 83 l-12 23 -13 -21z M1017 4820 c-8 -30 16 -52 65 -60 41 -6 45 -5 40 12 -5 20 -68 68 -88 68 -6 0 -14 -9 -17 -20z M2529 4778 c-11 -21 -7 -134 7 -185 8 -30 24 -19 24 17 0 16 7 35 15 44 18 17 20 70 4 115 -13 36 -33 40 -50 9z M830 4767 c0 -24 30 -116 40 -122 11 -7 1 92 -12 118 -10 20 -28 23 -28 4z M4660 4751 c0 -5 -9 -12 -19 -16 -23 -7 -101 -81 -101 -95 0 -26 50 -6 98 38 51 47 67 82 37 82 -8 0 -15 -4 -15 -9z M764 4719 c-7 -13 82 -106 92 -96 11 11 -9 43 -46 75 -27 23 -41 29 -46 21z M1887 4634 c-18 -18 -6 -91 21 -131 79 -118 125 -171 138 -159 10 9 8 18 -9 46 -12 19 -25 37 -29 38 -4 2 -8 25 -8 50 0 60 -15 115 -38 135 -20 19 -65 31 -75 21z M1030 4579 c0 -35 54 -169 68 -169 6 0 12 -8 12 -17 1 -17 2 -17 15 0 11 16 11 26 -5 71 -25 75 -47 114 -70 126 -17 9 -20 8 -20 -11z M697 4553 c19 -54 69 -92 112 -85 36 5 46 34 20 58 -11 9 -22 14 -25 11 -4 -4 -18 3 -32 13 -32 26 -84 28 -75 3z M1150 4486 c0 -36 52 -76 101 -76 47 0 57 29 12 32 -16 1 6 4 47 8 l75 6 -75 2 c-41 1 -85 8 -96 15 -12 6 -31 18 -43 25 -19 12 -21 11 -21 -12z M3909 4427 c-16 -27 -19 -51 -19 -149 0 -111 1 -118 20 -118 15 0 24 14 40 68 39 124 39 215 -1 225 -15 4 -25 -2 -40 -26z M4723 4375 c-30 -13 -33 -18 -33 -60 l0 -45 24 15 c27 18 49 48 60 83 9 26 -4 28 -51 7z M5002 4348 c-5 -7 -23 -40 -40 -73 -32 -65 -106 -146 -156 -172 -17 -9 -51 -21 -75 -28 -46 -11 -63 -28 -38 -38 7 -3 47 2 87 10 58 12 85 13 128 4 96 -19 162 -13 162 15 0 11 -19 14 -82 15 -46 0 -91 4 -101 8 -17 6 -17 8 2 25 11 10 44 25 73 32 34 8 43 13 27 13 -31 1 -44 24 -23 41 8 7 14 21 14 31 0 11 10 36 23 57 33 52 39 72 23 72 -7 0 -18 -6 -24 -12z M3632 4290 c-52 -37 -68 -69 -74 -145 -3 -33 -3 -54 0 -47 3 10 7 9 16 -4 12 -15 18 -14 79 15 69 33 101 66 95 98 -4 22 -37 30 -49 11 -6 -8 -7 10 -3 45 8 68 -2 72 -64 27z M5016 4271 c-11 -12 -16 -24 -12 -28 9 -9 39 22 34 37 -2 7 -10 4 -22 -9z M470 4264 c0 -9 8 -28 18 -42 10 -15 22 -33 27 -40 8 -15 -67 31 -102 62 -13 11 -23 14 -23 8 0 -7 -7 -12 -15 -12 -19 0 -19 -15 2 -50 20 -35 48 -48 118 -56 37 -5 55 -11 55 -20 0 -8 11 -14 25 -14 14 0 25 4 25 10 0 5 -22 43 -50 84 -49 73 -80 100 -80 70z M2382 4102 c-5 -9 -12 -42 -14 -72 -9 -96 18 -125 39 -43 17 66 17 120 -2 127 -8 3 -19 -2 -23 -12z M4235 3850 c36 -39 118 -80 162 -80 30 0 93 41 93 61 0 5 -14 15 -30 24 -25 13 -44 14 -107 6 -43 -5 -80 -6 -83 -1 -3 5 -19 12 -35 16 l-30 7 30 -33z M133 3667 c-19 -41 -15 -59 18 -86 30 -24 135 -55 151 -45 11 7 10 42 -2 49 -5 3 -10 11 -10 17 0 6 7 5 17 -3 12 -10 15 -10 9 -1 -13 22 -84 52 -125 52 -33 0 -40 4 -43 22 -3 21 -4 21 -15 -5z M5265 3631 c-16 -10 -43 -33 -60 -51 l-30 -32 83 4 c77 3 86 6 107 30 35 41 24 68 -29 68 -23 0 -54 -8 -71 -19z M400 3512 c0 -5 -53 -12 -117 -16 -64 -4 -120 -9 -125 -12 -16 -10 -8 -53 13 -65 51 -27 183 0 213 43 13 17 19 18 68 9 29 -5 66 -13 81 -16 22 -6 26 -4 21 9 -5 12 0 16 17 17 13 1 -3 7 -36 14 -106 22 -135 26 -135 17z M5090 3480 c0 -5 9 -10 20 -10 11 0 47 -13 80 -30 57 -29 121 -39 147 -22 22 14 19 45 -7 59 -30 15 -240 18 -240 3z M926 3272 c-12 -11 -6 -94 9 -122 16 -31 39 -47 86 -60 24 -7 29 -5 39 21 19 44 5 94 -34 124 -35 27 -90 47 -100 37z M500 3049 c0 -23 9 -62 20 -85 17 -33 30 -46 70 -62 34 -14 56 -32 70 -54 16 -28 109 -108 125 -108 3 0 5 7 5 15 0 12 7 14 28 9 15 -3 -8 11 -50 32 -42 20 -80 44 -83 53 -4 9 -9 46 -12 84 -5 61 -9 70 -41 98 -34 30 -59 43 -107 55 -24 6 -25 4 -25 -37z M5203 2779 c-18 -11 -35 -29 -38 -40 -7 -22 -20 -25 -32 -6 -8 13 -20 -26 -22 -74 -1 -30 25 -36 35 -7 4 15 9 17 20 7 8 -6 14 -18 14 -26 0 -11 7 -9 27 7 43 33 63 71 63 118 0 49 -14 53 -67 21z M5307 2622 c-34 -32 -86 -72 -115 -88 -51 -29 -61 -46 -29 -52 25 -5 198 81 229 114 15 16 30 41 33 57 7 25 5 27 -24 27 -25 0 -45 -13 -94 -58z M447 2652 c-10 -10 -15 -21 -12 -24 7 -7 75 24 75 34 0 15 -47 8 -63 -10z M263 2600 c-12 -5 -26 -18 -32 -28 -8 -15 -6 -24 13 -41 33 -31 84 -27 160 13 68 36 68 47 1 51 -16 1 -50 5 -75 8 -25 4 -55 3 -67 -3z M996 2540 c-37 -11 -102 -74 -115 -112 l-10 -28 58 0 c48 0 65 5 98 29 49 35 87 86 79 106 -6 17 -62 19 -110 5z M673 2324 c-43 -18 -42 -43 1 -88 33 -35 35 -36 114 -36 70 0 80 2 78 18 0 10 6 16 16 16 13 -1 9 8 -18 40 -19 22 -45 46 -57 53 -29 16 -94 15 -134 -3z M4790 2120 c-9 -17 -5 -20 43 -29 72 -15 166 -19 169 -9 2 5 11 6 21 3 20 -8 23 -35 5 -35 -7 -1 -2 -7 12 -15 29 -17 113 -20 141 -5 24 13 25 36 2 48 -10 5 -58 12 -108 15 -49 3 -117 12 -150 20 -110 28 -124 28 -135 7z M4881 2021 c6 -17 30 -50 53 -75 33 -36 49 -46 74 -46 25 0 32 4 32 19 0 25 -60 77 -99 86 -17 4 -36 15 -41 26 -17 30 -30 23 -19 -10z\";\n","import { TREE_MARK_PATH } from \"./treeMarkPath\";\n\nexport function TreeMarkIcon({ className }: { className?: string }) {\n return (\n <svg viewBox=\"0 0 551 567\" fill=\"currentColor\" className={className} aria-hidden>\n <path transform=\"translate(0 567) scale(0.1 -0.1)\" d={TREE_MARK_PATH} />\n </svg>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { PanelSection, Skeleton } from \"@behindthemusictree/ui\";\nimport { z } from \"zod\";\n\nimport type { GenreMusicSelection } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaOverview } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useFetchGenreOverview } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaPlaylistMinimum, type GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { ClampedText } from \"./ClampedText\";\nimport CommonsPhoto from \"./CommonsPhoto\";\nimport { GenrePlaylistTracks, type GenrePlaylistTracksSlots } from \"./GenrePlaylistTracks\";\nimport type { RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\nimport { SiWikidata, SiWikipedia } from \"react-icons/si\";\n\nexport type GenreDetailSlots<O extends CriteriaOverview> = {\n /** Replaces the body of the default Summary section; the title and frame stay. */\n renderSummary?: (overview: O) => ReactNode;\n /** Replaces the body of the default Essential section (e.g. \"Essential songs\"); the title and frame stay. */\n renderEssentialTracks?: (overview: O) => ReactNode;\n};\n\nexport type GenreDetailExtrasProps<O extends CriteriaOverview> = GenreDetailSlots<O> & GenrePlaylistTracksSlots & {\n genreUuid: GenreUuid;\n genrePlaylist: CriteriaPlaylistMinimum | null;\n genreName?: string;\n selection?: GenreMusicSelection;\n wikidataId?: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n criteriaOverviewSchema?: z.ZodType<O, unknown>;\n renderGenreDetailExtras?: (overview: O) => ReactNode;\n renderArtistLink?: RenderArtistLink;\n renderSongLink?: RenderSongLink;\n /** When set, the tracks list shows only this artist's songs in the genre. */\n artist?: { uuid: string; name: string } | null;\n /** genre-tree-view's Family section, placed right after the Summary. */\n family: ReactNode;\n};\n\n// Owns the overview fetch so its pending → success transitions re-render only the info panel,\n// not the tree that renders it.\nexport function GenreDetailExtras<O extends CriteriaOverview>({\n genreUuid,\n genrePlaylist,\n genreName,\n selection,\n wikidataId,\n scope,\n getBackendBaseUrl,\n criteriaOverviewSchema,\n renderGenreDetailExtras,\n renderArtistLink,\n renderSongLink,\n renderSummary,\n renderEssentialTracks,\n family,\n ...trackSlots\n}: GenreDetailExtrasProps<O>) {\n const trackNoun = useTrackNoun();\n const { data: overview, isPending } = useFetchGenreOverview<O>(\n genreUuid,\n scope,\n getBackendBaseUrl,\n criteriaOverviewSchema,\n );\n\n if (isPending) {\n return (\n <>\n <PanelSection title=\"Summary\">\n <div aria-busy=\"true\" data-testid=\"genre-detail-extras-skeleton\">\n <Skeleton className=\"h-4 w-3/4\" />\n </div>\n </PanelSection>\n {family}\n </>\n );\n }\n if (!overview) return <>{family}</>;\n\n const { summary, summarySourceUrl, essentialSongs, image } = overview;\n const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;\n\n return (\n <>\n {image && <CommonsPhoto image={image} alt={overview.name} creditLabel=\"Image\" />}\n {(summarySourceUrl || wikidataUrl) && (\n <PanelSection title=\"Links\">\n <div className=\"flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]\">\n {summarySourceUrl && (\n <a\n href={summarySourceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]\"\n >\n <SiWikipedia aria-hidden=\"true\" className=\"h-3.5 w-3.5\" />\n Wikipedia\n </a>\n )}\n {wikidataUrl && (\n <a\n href={wikidataUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]\"\n >\n <SiWikidata aria-hidden=\"true\" className=\"h-3.5 w-3.5\" />\n Wikidata\n </a>\n )}\n </div>\n </PanelSection>\n )}\n <PanelSection title=\"Summary\">\n {renderSummary ? (\n renderSummary(overview)\n ) : (\n <ClampedText key={genreUuid} className=\"text-body text-[var(--color-text)]\">\n {summary ?? \"—\"}\n </ClampedText>\n )}\n </PanelSection>\n {family}\n {renderGenreDetailExtras?.(overview)}\n {(renderEssentialTracks || essentialSongs) && (\n <PanelSection title={`Essential ${trackNoun.plural}`}>\n {renderEssentialTracks ? (\n renderEssentialTracks(overview)\n ) : essentialSongs && essentialSongs.length > 0 ? (\n <ul className=\"text-body text-[var(--color-text)]\">\n {essentialSongs.map((track) => (\n <li key={track.uuid} className=\"py-1\">\n {track.title}\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-body text-[var(--color-text)]\">—</p>\n )}\n </PanelSection>\n )}\n <GenrePlaylistTracks\n genreUuid={genreUuid}\n genrePlaylist={genrePlaylist}\n genreName={genreName}\n selection={selection}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n {...trackSlots}\n />\n </>\n );\n}\n","\"use client\";\n\nimport { useLayoutEffect, useRef, useState } from \"react\";\n\ntype ClampedTextProps = {\n children: string;\n className?: string;\n};\n\nexport function ClampedText({ children, className = \"\" }: ClampedTextProps) {\n const ref = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (!element || expanded) return;\n setOverflows(element.scrollHeight > element.clientHeight);\n }, [children, expanded]);\n\n return (\n <>\n <p ref={ref} className={`${className} ${expanded ? \"\" : \"line-clamp-3\"}`}>\n {children}\n </p>\n {(overflows || expanded) && (\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((value) => !value)}\n className=\"mt-1 text-caption text-[var(--color-text-muted)] underline hover:text-[var(--color-text)]\"\n >\n {expanded ? \"Show less\" : \"Show more\"}\n </button>\n )}\n </>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { CommonsImage } from \"@behindthemusictree/app-kit/genre-tree\";\n\nfunction ExternalLink({ href, children }: { href: string; children: ReactNode }) {\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"underline-offset-2 hover:underline\">\n {children}\n </a>\n );\n}\n\nexport default function CommonsPhoto({\n image,\n alt,\n creditLabel = \"Photo\",\n}: {\n image: CommonsImage;\n alt: string;\n creditLabel?: string;\n}) {\n return (\n <figure className=\"flex flex-col gap-1.5\">\n <img src={image.url} alt={alt} className=\"h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded\" />\n <figcaption className=\"text-caption text-[var(--color-text-muted)]\">\n {creditLabel}: <ExternalLink href={image.pageUrl}>{image.author ?? \"Wikimedia Commons\"}</ExternalLink>,{\" \"}\n {image.licenseUrl ? <ExternalLink href={image.licenseUrl}>{image.license}</ExternalLink> : image.license}\n </figcaption>\n </figure>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState, type ReactNode } from \"react\";\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport { z } from \"zod\";\nimport { FaPlay, FaPause } from \"react-icons/fa\";\nimport { PanelSection, RingLoader, Skeleton } from \"@behindthemusictree/ui\";\n\nimport { useSession } from \"@behindthemusictree/app-kit/auth\";\nimport { usePlaybackContext, usePlaybackFetch } from \"@behindthemusictree/app-kit/transport\";\nimport { PaginatedResponseSchema } from \"@behindthemusictree/app-kit/transport\";\nimport { parseWithLog } from \"@behindthemusictree/app-kit/transport\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport { PlayStates } from \"@behindthemusictree/app-kit/player\";\nimport { usePopup } from \"@behindthemusictree/app-kit/popup\";\nimport InternalErrorPopup from \"../popup/InternalErrorPopup\";\nimport { AppError, ErrorCode } from \"@behindthemusictree/app-kit/transport\";\nimport { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { genreMusicQueryParams, type GenreMusicSelection } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { genrePlaylistQueryKeys } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { libraryEndpoints, libraryQueryKeys } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { CriteriaPlaylistMinimum, type GenreUuid } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { isSong, songUnplayableReason, SongDetailedSchema } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { GenrePlaylistTracksPage, TracksFailureAlreadyReportedError, useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { MusicBrainzRecordingLink } from \"./MusicBrainzRecordingLink\";\nimport { ArtistNames, RenderArtistLink, type RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { capitalize, useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\n\nconst CATALOGUE_PAGE_SIZE = 100;\n// withTotal=false: the backend skips COUNT(*) and pages by keyset cursor, so huge genre subtrees\n// stay O(page) at any depth; page numbers and totals are then null.\nconst SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({\n overallTotal: z.number().nullable(),\n page: z.number().nullable(),\n totalPages: z.number().nullable(),\n});\n\n// Container query on the list (arbitrary variant: Tailwind 3 core has no `@container`): once the\n// list is wide (expanded info panel), title, artist and album become columns instead of one line.\n// Class names stay literal so Tailwind's scanner sees them.\nconst TEXT_CELL = \"min-w-0 flex-1 truncate [@container(min-width:40rem)]:flex [@container(min-width:40rem)]:gap-2\";\nconst TITLE_CELL = \"[@container(min-width:40rem)]:flex-[2] [@container(min-width:40rem)]:truncate\";\nconst COLUMN_CELL = \"[@container(min-width:40rem)]:flex-1 [@container(min-width:40rem)]:truncate\";\nconst ALBUM_CELL = `hidden [@container(min-width:40rem)]:block ${COLUMN_CELL}`;\nconst SEPARATOR = \"[@container(min-width:40rem)]:hidden\";\n\nconst nextCursor = (next: string): string => {\n const cursor = new URL(next).searchParams.get(\"cursor\");\n if (!cursor) throw new Error(`Songs next link has no cursor: ${next}`);\n return cursor;\n};\n\n// Songs are not narrowed to SongDetailed here: \"me\" scope lists uploaded tracks too.\nexport type GenrePlaylistTracksSlots = {\n /** Rendered first in each row, e.g. a selection checkbox. `index` is the row's position in the loaded list. */\n renderSongLeading?: (song: TrackBase, index: number) => ReactNode;\n /** Rendered last in each row. The song's own genre is `song.genre`. */\n renderSongActions?: (song: TrackBase) => ReactNode;\n /** Rendered between the title and the list, e.g. a \"+ Link\" button or a selection bar. */\n renderTracksToolbar?: () => ReactNode;\n};\n\nexport type GenrePlaylistTracksProps = GenrePlaylistTracksSlots & {\n genreUuid: GenreUuid;\n genrePlaylist: CriteriaPlaylistMinimum | null;\n genreName?: string;\n selection?: GenreMusicSelection;\n scope: Scope;\n getBackendBaseUrl: () => string;\n /** When set, artist names render through it (e.g. a router `Link`). */\n renderArtistLink?: RenderArtistLink;\n /** When set, song titles render through it (e.g. open the song panel) instead of linking to MusicBrainz. */\n renderSongLink?: RenderSongLink;\n /** When set, lists and plays only this artist's songs in the genre. */\n artist?: { uuid: string; name: string } | null;\n};\n\n/**\n * \"reference\" lists the genre's whole songs catalogue (genre subtree), playable or not, while\n * row playback uses the playable catalogue. The genre Play action uses playlist members. Other scopes have no catalogue endpoint; their\n * playlist is the catalogue (e.g. hear's uploaded tracks are always playable).\n */\nexport function GenrePlaylistTracks({\n genreUuid,\n genrePlaylist,\n genreName: selectedGenreName,\n selection,\n scope,\n getBackendBaseUrl,\n renderArtistLink,\n renderSongLink,\n renderSongLeading,\n renderSongActions,\n renderTracksToolbar,\n artist = null,\n}: GenrePlaylistTracksProps) {\n const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = useTrackList();\n const { session, sessionRestored } = useSession();\n const { playerTrackObject, playState, handlePlayPauseAction } = usePlayer();\n const { showPopup } = usePopup();\n const trackNoun = useTrackNoun();\n const uuid = genrePlaylist?.uuid;\n const genreName = selectedGenreName ?? genrePlaylist?.name ?? \"Genre\";\n\n const { fetchBound } = usePlaybackFetch(getBackendBaseUrl);\n const playback = usePlaybackContext();\n\n const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteQuery({\n queryKey: [...(\n scope === \"me\"\n ? (uuid ? genrePlaylistQueryKeys.me.tracks(uuid) : [\"missing-personal-genre-playlist\", genreUuid])\n : artist\n ? [...libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), \"artist\", artist.uuid]\n : libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection)\n ), ...(playback.key ? [playback.key] : [])],\n queryFn: async ({ pageParam }): Promise<Omit<GenrePlaylistTracksPage<TrackBase>, \"total\" | \"nextPage\"> & { total: number | null; nextPage: number | string | null }> => {\n if (scope === \"me\") {\n if (!uuid) throw new Error(\"Personal genre has no playlist\");\n return fetchGenrePlaylistTracksPage(uuid, scope, Number(pageParam));\n }\n const response = await fetchBound(\n libraryEndpoints.reference.songs.list(),\n true,\n false,\n {},\n { genre: genreUuid, ...genreMusicQueryParams(selection), ...(artist && { artist: artist.uuid }), pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...(pageParam && { cursor: pageParam }) },\n );\n const parsed = parseWithLog(SongPageSchema, response, \"GenrePlaylistTracks\");\n return { tracks: parsed.results, total: parsed.overallTotal, nextPage: parsed.next ? nextCursor(parsed.next) : null };\n },\n initialPageParam: scope === \"me\" ? 1 : \"\",\n getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,\n enabled: playback.ready && (scope !== \"me\" || (uuid !== undefined && sessionRestored && !!session?.accessToken)),\n retry: (failureCount, error) => failureCount < 1 && error instanceof DOMException && error.name === \"AbortError\",\n retryDelay: 0,\n });\n\n // State, not a ref object: PanelSection unmounts its body when collapsed, so the observer must\n // re-attach when the sentinel remounts.\n const [sentinel, setSentinel] = useState<HTMLLIElement | null>(null);\n useEffect(() => {\n if (!hasNextPage || isFetchingNextPage || !sentinel) return;\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n void fetchNextPage();\n }\n });\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasNextPage, isFetchingNextPage, fetchNextPage, sentinel]);\n\n const pages = data?.pages ?? [];\n const tracks = pages.flatMap((page) => page.tracks);\n const total = pages[0]?.total ?? undefined;\n\n const play = (startSongUuid: string) => {\n const started = artist\n ? playNewTrackListFromArtist(artist, scope, {\n startSongUuid, ordering: \"title\", genreUuid, ...(selection && { selection }),\n })\n : scope === \"reference\"\n ? playNewTrackListFromGenreCatalogue({ uuid: genreUuid, name: genreName }, scope, { startSongUuid, ...(selection && { selection }) })\n : genrePlaylist ? playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid }) : Promise.reject(new Error(\"Personal genre has no playlist\"));\n started.catch((error) => {\n console.error(\"Failed to play genre playlist:\", error);\n if (error instanceof TracksFailureAlreadyReportedError) return;\n showPopup(<InternalErrorPopup errorCode={error instanceof AppError ? error.code : ErrorCode.CLIENT_UNKNOWN} />);\n });\n };\n\n return (\n <PanelSection title={`${capitalize(trackNoun.plural)}${total !== undefined ? ` (${total})` : \"\"}`}>\n <div>\n {renderTracksToolbar?.()}\n {scope === \"me\" && !genrePlaylist ? (\n <p>—</p>\n ) : isPending ? (\n <Skeleton className=\"h-4 w-3/4\" aria-busy=\"true\" />\n ) : isError && tracks.length === 0 ? (\n <p role=\"alert\">\n Couldn&apos;t load {trackNoun.plural}.{\" \"}\n <button type=\"button\" className=\"underline\" onClick={() => void refetch()}>\n Retry\n </button>\n </p>\n ) : tracks.length === 0 ? (\n <p>—</p>\n ) : (\n <ul className=\"mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]\" aria-label={`${genreName} ${trackNoun.plural}`}>\n {tracks.map((track, index) => {\n const label = track.artists?.length\n ? `${track.title} — ${track.artists.map((artist) => artist.name).join(\", \")}`\n : track.title;\n const isCurrent = playerTrackObject?.track.id === track.uuid;\n const isPlaying = isCurrent && playState === PlayStates.PLAYING;\n const text = (\n <span className={TEXT_CELL}>\n <span className={TITLE_CELL}>\n {renderSongLink ? (\n renderSongLink(track)\n ) : isSong(track) ? (\n <MusicBrainzRecordingLink song={track} className=\"hover:underline focus-visible:underline\">\n {track.title}\n </MusicBrainzRecordingLink>\n ) : (\n track.title\n )}\n </span>\n {track.artists?.length ? <span className={SEPARATOR}>{\" — \"}</span> : null}\n <span className={COLUMN_CELL}>\n {track.artists?.length ? (\n <ArtistNames artists={track.artists} renderArtistLink={renderArtistLink} />\n ) : null}\n </span>\n {track.album && <span className={ALBUM_CELL}>{track.album.name}</span>}\n </span>\n );\n const leading = renderSongLeading?.(track, index);\n const actions = renderSongActions?.(track);\n const isUnplayable = isSong(track) && songUnplayableReason(track) !== null;\n if (isUnplayable) {\n return (\n <li key={track.uuid} className=\"flex min-h-8 items-center gap-1 px-1 opacity-50\">\n {leading}\n <button\n type=\"button\"\n disabled\n aria-disabled=\"true\"\n aria-label={label}\n className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed\"\n >\n <FaPlay size={10} />\n </button>\n {text}\n {actions}\n </li>\n );\n }\n return (\n <li\n key={track.uuid}\n className={`group flex min-h-8 items-center gap-1 rounded px-1 hover:bg-[var(--color-neutral-100)] ${isCurrent ? \"font-medium text-[var(--color-primary)]\" : \"\"}`}\n >\n {leading}\n <button\n type=\"button\"\n aria-label={`${isPlaying ? \"Pause\" : \"Play\"} ${label}`}\n className={`flex h-6 w-6 shrink-0 items-center justify-center rounded-full cursor-pointer group-hover:opacity-100 focus-visible:opacity-100 ${isCurrent && playState !== PlayStates.STOPPED ? \"opacity-100\" : \"opacity-0 [@media(pointer:coarse)]:opacity-100\"}`}\n onClick={() => (isCurrent ? handlePlayPauseAction() : play(track.uuid))}\n >\n {isCurrent && playState === PlayStates.LOADING ? (\n <RingLoader size={10} />\n ) : isPlaying ? (\n <FaPause size={10} />\n ) : (\n <FaPlay size={10} />\n )}\n </button>\n {text}\n {actions}\n </li>\n );\n })}\n {hasNextPage && <li ref={setSentinel} aria-hidden=\"true\" className=\"h-4\" />}\n </ul>\n )}\n </div>\n </PanelSection>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { SongDetailed, musicBrainzRecordingUrl } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport function MusicBrainzRecordingLink({\n song,\n children,\n className = \"\",\n}: {\n song: SongDetailed;\n children: ReactNode;\n className?: string;\n}) {\n const url = musicBrainzRecordingUrl(song);\n if (!url) return <>{children}</>;\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`View ${song.title} on MusicBrainz`}\n className={className}\n onClick={(event) => event.stopPropagation()}\n >\n {children}\n </a>\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\n\nimport {\n CriteriaPlaylistSimple,\n ReparentCandidate,\n type GenreUuid,\n getReparentCandidates,\n useUpdateGenre,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport BasePopup from \"../popup/BasePopup\";\nimport { PopupButtons } from \"../popup/PopupButtons\";\nimport GenreSearch from \"./GenreSearch\";\n\nexport type ParentChange = { genre: GenreUuid; from: GenreUuid | null; to: GenreUuid | null };\n\ntype ChangeParentPopupProps = {\n genrePlaylist: ReparentCandidate;\n genrePlaylists: CriteriaPlaylistSimple[];\n scope: Scope;\n getBackendBaseUrl: () => string;\n onClose: () => void;\n onParentChanged?: (change: ParentChange) => void;\n};\n\nexport default function ChangeParentPopup({\n genrePlaylist,\n genrePlaylists,\n scope,\n getBackendBaseUrl,\n onClose,\n onParentChanged,\n}: ChangeParentPopupProps) {\n const { mutate, isPending, formErrors } = useUpdateGenre(scope, getBackendBaseUrl);\n const candidates = useMemo(\n () => getReparentCandidates(genrePlaylists, genrePlaylist.uuid),\n [genrePlaylists, genrePlaylist.uuid],\n );\n\n const [confirmingRoot, setConfirmingRoot] = useState(false);\n\n const handleMove = (to: GenreUuid | null) => {\n const genre = genrePlaylist.criteria.uuid;\n const parentPlaylistUuid = genrePlaylist.parent?.uuid;\n const from = parentPlaylistUuid\n ? (genrePlaylists.find(({ uuid }) => uuid === parentPlaylistUuid)?.criteria?.uuid ?? null)\n : null;\n mutate(\n { uuid: genre, data: { parent: to } },\n {\n onSuccess: () => {\n onClose();\n onParentChanged?.({ genre, from, to });\n },\n },\n );\n };\n\n const handleSelect = (newParent: ReparentCandidate) => handleMove(newParent.criteria.uuid);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n return (\n <BasePopup title={`Change parent of ${genrePlaylist.name}`} onClose={onClose} showCancelButton fitContent>\n <p className=\"mb-3 text-body text-[var(--color-text-muted)]\">\n Current parent: {genrePlaylist.parent?.name ?? \"none\"}\n </p>\n {genrePlaylist.parent &&\n (confirmingRoot ? (\n <div className=\"mb-3 text-sm\">\n <p className=\"mb-2\">\n {genrePlaylist.name} and its descendants will no longer be under {genrePlaylist.parent.name}.\n </p>\n <PopupButtons alignment=\"left\">\n <Button disabled={isPending} onClick={() => handleMove(null)}>\n Confirm\n </Button>\n <Button variant=\"secondary\" disabled={isPending} onClick={() => setConfirmingRoot(false)}>\n Back\n </Button>\n </PopupButtons>\n </div>\n ) : (\n <div className=\"mb-3\">\n <Button variant=\"secondary\" onClick={() => setConfirmingRoot(true)}>\n Make root\n </Button>\n </div>\n ))}\n <div aria-busy={isPending} className={isPending ? \"pointer-events-none opacity-60\" : undefined}>\n <GenreSearch\n genrePlaylists={candidates}\n onSelect={handleSelect}\n placeholder=\"Search a new parent…\"\n />\n </div>\n {formErrors.length > 0 && (\n <p role=\"alert\" className=\"mt-3 text-body text-[var(--color-red-500)]\">\n {formErrors.map(({ message }) => message).join(\" \")}\n </p>\n )}\n </BasePopup>\n );\n}\n","\"use client\";\n\nimport { Skeleton } from \"@behindthemusictree/ui\";\nimport {\n useArtist,\n type RenderArtistLink,\n type RenderPlaceLink,\n type RenderSongLink,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport ArtistActionBand from \"./ArtistActionBand\";\nimport ArtistHeader from \"./ArtistHeader\";\nimport ArtistPhoto from \"./ArtistPhoto\";\nimport ArtistMembers from \"./ArtistMembers\";\nimport ArtistDiscography from \"./ArtistDiscography\";\nimport ArtistSongs from \"./ArtistSongs\";\nimport ShareActionButton from \"../ShareActionButton\";\nimport type { GetGenreTreeShareUrl } from \"../share\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { OverlayPanel } from \"../overlayPanel\";\n\nexport interface ArtistPanelOptions {\n uuid: string | null;\n scope?: Scope;\n getBackendBaseUrl: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n /** Renders member and song artist names. */\n renderArtistLink: RenderArtistLink;\n renderSongLink?: RenderSongLink;\n /** Renders the artist's origin as a link to its map region; plain text when omitted. */\n renderPlaceLink?: RenderPlaceLink;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n onClose: () => void;\n}\n\n/** The artist detail overlay panel for `uuid`, or undefined when no artist is set. */\nexport function useArtistPanel({\n uuid,\n scope,\n getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n expanded,\n onExpandedChange,\n onClose,\n}: ArtistPanelOptions): OverlayPanel | undefined {\n const result = useArtist(uuid, getBackendBaseUrl);\n\n const panel = { expanded, onExpandedChange, onClose };\n switch (result.status) {\n case \"idle\":\n return undefined;\n case \"loading\":\n return {\n ...panel,\n title: \"Artist\",\n content: (\n <div aria-busy=\"true\" className=\"flex flex-col gap-2.5\">\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-16 mt-2.5\" />\n <Skeleton className=\"h-16\" />\n </div>\n ),\n };\n case \"not-found\":\n return {\n ...panel,\n title: \"Artist not found\",\n content: <p className=\"text-[var(--color-text-muted)]\">This artist does not exist.</p>,\n };\n case \"error\":\n return {\n ...panel,\n title: \"Artist\",\n content: <p className=\"text-red-600\">Could not load this artist.</p>,\n };\n case \"success\": {\n const { artist } = result;\n const shareTarget = scope\n ? { kind: \"artist\" as const, uuid: artist.uuid, name: artist.name, scope }\n : undefined;\n const shareUrl = shareTarget ? getShareUrl?.(shareTarget) : undefined;\n return {\n ...panel,\n title: artist.name,\n content: (\n <>\n <ArtistActionBand\n artist={artist}\n share={shareTarget && shareUrl ? <ShareActionButton target={shareTarget} url={shareUrl} /> : undefined}\n />\n {artist.image && <ArtistPhoto image={artist.image} name={artist.name} />}\n <ArtistHeader artist={artist} renderPlaceLink={renderPlaceLink} />\n <ArtistMembers title=\"Members\" memberships={artist.members} renderArtistLink={renderArtistLink} />\n <ArtistMembers title=\"Member of\" memberships={artist.memberOf} renderArtistLink={renderArtistLink} />\n {artist.tracksCount > 0 && (\n <ArtistSongs\n artist={{ uuid: artist.uuid, name: artist.name }}\n getBackendBaseUrl={getBackendBaseUrl}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n )}\n </>\n ),\n extraContent: artist.albums.length > 0 ? <ArtistDiscography albums={artist.albums} /> : undefined,\n };\n }\n }\n}\n","\"use client\";\n\nimport { Pause, Play } from \"lucide-react\";\nimport { ActionBand, ActionButton, PanelBleed } from \"@behindthemusictree/ui\";\nimport { TrackListOriginType, useTrackList, type ArtistDetailed, type SongDetailed } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport type { ReactNode } from \"react\";\n\ntype ArtistActionBandProps = {\n artist: Pick<ArtistDetailed, \"uuid\" | \"name\" | \"playableTracksCount\">;\n /** Share button, when the host provides a share URL. */\n share?: ReactNode;\n};\n\n/** The artist panel's action band: Play over the artist's playable songs, with their count. */\nexport default function ArtistActionBand({ artist, share }: ArtistActionBandProps) {\n const { trackList, playNewTrackListFromArtist } = useTrackList<SongDetailed>();\n const { isPlaying, setIsPlaying } = usePlayer();\n const origin = trackList?.origin;\n const isCurrent = origin?.type === TrackListOriginType.ARTIST && origin.uuid === artist.uuid;\n const playing = isCurrent && isPlaying;\n const handleClick = () => {\n if (isCurrent) {\n setIsPlaying(!isPlaying);\n return;\n }\n playNewTrackListFromArtist({ uuid: artist.uuid, name: artist.name }, \"reference\", { ordering: \"title\" }).catch((error) => {\n console.error(\"Failed to load artist tracks:\", error);\n });\n };\n return (\n <PanelBleed>\n <ActionBand>\n <ActionButton\n icon={playing ? <Pause aria-hidden=\"true\" className=\"w-5 h-5\" /> : <Play aria-hidden=\"true\" className=\"w-5 h-5\" />}\n label={playing ? \"Pause\" : \"Play\"}\n caption={String(artist.playableTracksCount)}\n disabled={artist.playableTracksCount === 0}\n title={artist.playableTracksCount === 0 ? \"No playable songs\" : undefined}\n onClick={handleClick}\n />\n {share}\n </ActionBand>\n </PanelBleed>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { FieldList } from \"@behindthemusictree/ui\";\nimport type { ArtistDetailed, ArtistOrigin, RenderPlaceLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport ArtistLinks, { artistLinks } from \"./ArtistLinks\";\nimport { formatYears } from \"./formatYears\";\n\nconst countryNames = new Intl.DisplayNames([\"en\"], { type: \"region\" });\n\nfunction originLabel(artist: ArtistDetailed, origin: ArtistOrigin): string {\n if (origin.source === \"area\") return \"From\";\n if (artist.type === \"person\") return \"Born in\";\n if (artist.type === \"group\") return \"Formed in\";\n return \"From\";\n}\n\nfunction OriginValue({\n origin,\n country,\n renderPlaceLink,\n}: {\n origin: ArtistOrigin;\n country: string | undefined;\n renderPlaceLink?: RenderPlaceLink;\n}) {\n const place =\n renderPlaceLink && origin.regionId !== null ? renderPlaceLink({ ...origin, regionId: origin.regionId }) : origin.name;\n return (\n <>\n {place}\n {country && origin.kind !== \"country\" && `, ${country}`}\n </>\n );\n}\n\nexport default function ArtistHeader({\n artist,\n renderPlaceLink,\n}: {\n artist: ArtistDetailed;\n renderPlaceLink?: RenderPlaceLink;\n}) {\n const fields: { label: string; value: ReactNode }[] = [];\n if (artist.type) fields.push({ label: \"Type\", value: artist.type.charAt(0).toUpperCase() + artist.type.slice(1) });\n const country = artist.country ? countryNames.of(artist.country) : undefined;\n if (artist.origin) {\n fields.push({\n label: originLabel(artist, artist.origin),\n value: <OriginValue origin={artist.origin} country={country} renderPlaceLink={renderPlaceLink} />,\n });\n }\n if (country && !artist.origin) fields.push({ label: \"Country\", value: country });\n const years = formatYears(artist.beginYear, artist.endYear, artist.ended);\n if (years) fields.push({ label: \"Active\", value: years });\n const links = artistLinks(artist);\n if (links.length > 0) fields.push({ label: \"Links\", value: <ArtistLinks links={links} /> });\n\n if (fields.length === 0) return null;\n return <FieldList items={fields} />;\n}\n","import type { ComponentType } from \"react\";\nimport { Globe, Share2 } from \"lucide-react\";\nimport {\n SiBandcamp,\n SiDiscogs,\n SiMusicbrainz,\n SiSoundcloud,\n SiSpotify,\n SiWikidata,\n SiWikipedia,\n SiYoutube,\n} from \"react-icons/si\";\nimport { Chip } from \"@behindthemusictree/ui\";\nimport type { ArtistDetailed, ArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\n\nconst LINK_KINDS: Record<ArtistLink[\"kind\"], { label: string; Icon: ComponentType<{ className?: string }> }> = {\n official: { label: \"Official website\", Icon: Globe },\n wikipedia: { label: \"Wikipedia\", Icon: SiWikipedia },\n wikidata: { label: \"Wikidata\", Icon: SiWikidata },\n spotify: { label: \"Spotify\", Icon: SiSpotify },\n youtube: { label: \"YouTube\", Icon: SiYoutube },\n bandcamp: { label: \"Bandcamp\", Icon: SiBandcamp },\n soundcloud: { label: \"SoundCloud\", Icon: SiSoundcloud },\n discogs: { label: \"Discogs\", Icon: SiDiscogs },\n social: { label: \"Social\", Icon: Share2 },\n};\n\nfunction socialLabel(url: string): string {\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n } catch {\n return LINK_KINDS.social.label;\n }\n}\n\ninterface ArtistLinkItem {\n key: string;\n url: string;\n Icon: ComponentType<{ className?: string }>;\n label: string;\n}\n\nexport function artistLinks(artist: ArtistDetailed): ArtistLinkItem[] {\n const links = artist.links.map(({ kind, url }) => ({\n key: `${kind}-${url}`,\n url,\n Icon: LINK_KINDS[kind].Icon,\n label: kind === \"social\" ? socialLabel(url) : LINK_KINDS[kind].label,\n }));\n if (artist.musicbrainzArtistId) {\n links.push({\n key: \"musicbrainz\",\n url: `https://musicbrainz.org/artist/${artist.musicbrainzArtistId}`,\n Icon: SiMusicbrainz,\n label: \"MusicBrainz\",\n });\n }\n return links;\n}\n\nexport default function ArtistLinks({ links }: { links: ArtistLinkItem[] }) {\n return (\n <ul className=\"flex flex-wrap gap-1.5\">\n {links.map(({ key, url, Icon, label }) => (\n <li key={key}>\n <Chip href={url} icon={<Icon className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" />}>\n {label}\n </Chip>\n </li>\n ))}\n </ul>\n );\n}\n","/** \"1994–present\", \"1994–2008\", \"?–2008\", or null when nothing is known. */\nexport function formatYears(beginYear: number | null, endYear: number | null, ended: boolean): string | null {\n if (beginYear === null && endYear === null) return ended ? \"ended\" : null;\n const end = endYear ?? (ended ? \"?\" : \"present\");\n return `${beginYear ?? \"?\"}–${end}`;\n}\n","import type { ArtistImage } from \"@behindthemusictree/app-kit/genre-tree\";\nimport CommonsPhoto from \"../CommonsPhoto\";\n\nexport default function ArtistPhoto({ image, name }: { image: ArtistImage; name: string }) {\n return <CommonsPhoto image={image} alt={name} />;\n}\n","import type { ArtistMembership, RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PanelGroup, PanelSection } from \"@behindthemusictree/ui\";\nimport { formatYears } from \"./formatYears\";\n\ninterface MembershipListProps {\n title: string;\n memberships: ArtistMembership[];\n renderArtistLink: RenderArtistLink;\n}\n\nfunction MembershipList({ title, memberships, renderArtistLink }: MembershipListProps) {\n if (memberships.length === 0) return null;\n return (\n <PanelGroup title={title}>\n <ul>\n {memberships.map((membership, index) => {\n const details = [\n formatYears(membership.beginYear, membership.endYear, membership.ended),\n ...membership.roles,\n ];\n const detailsText = details.filter(Boolean).join(\" · \");\n return (\n // A member can have several periods in the same group.\n <li key={`${membership.artist.uuid}-${index}`} className=\"truncate py-0.5\" title={detailsText || undefined}>\n <span className=\"font-medium text-[var(--color-text)]\">{renderArtistLink(membership.artist)}</span>\n {detailsText && <span className=\"text-[var(--color-text-muted)]\"> — {detailsText}</span>}\n </li>\n );\n })}\n </ul>\n </PanelGroup>\n );\n}\n\nexport default function ArtistMembers({ title, memberships, renderArtistLink }: MembershipListProps) {\n if (memberships.length === 0) return null;\n const isCurrent = (membership: ArtistMembership) => !membership.ended && membership.endYear === null;\n\n return (\n <PanelSection title={title}>\n <MembershipList title=\"Current\" memberships={memberships.filter(isCurrent)} renderArtistLink={renderArtistLink} />\n <MembershipList\n title=\"Past\"\n memberships={memberships.filter((membership) => !isCurrent(membership))}\n renderArtistLink={renderArtistLink}\n />\n </PanelSection>\n );\n}\n","import type { ArtistAlbum } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PanelGroup, PanelSection } from \"@behindthemusictree/ui\";\n\nconst GROUPS = [\"Albums\", \"EPs\", \"Singles\", \"Live\", \"Compilations\", \"Other\"] as const;\ntype Group = (typeof GROUPS)[number];\n\nconst PRIMARY_GROUPS: Record<string, Group> = { album: \"Albums\", ep: \"EPs\", single: \"Singles\" };\n\n// Secondary types win over the primary one: a live album belongs with live releases, not studio albums.\nexport function discographyGroup({ primaryType, secondaryTypes }: ArtistAlbum): Group {\n const secondary = secondaryTypes.map((type) => type.toLowerCase());\n if (secondary.includes(\"live\")) return \"Live\";\n if (secondary.includes(\"compilation\")) return \"Compilations\";\n return PRIMARY_GROUPS[primaryType?.toLowerCase() ?? \"\"] ?? \"Other\";\n}\n\nfunction byYear(a: ArtistAlbum, b: ArtistAlbum): number {\n if (a.year !== b.year) {\n if (a.year === null) return 1;\n if (b.year === null) return -1;\n return a.year.localeCompare(b.year);\n }\n return a.name.localeCompare(b.name);\n}\n\nexport default function ArtistDiscography({ albums }: { albums: ArtistAlbum[] }) {\n if (albums.length === 0) return null;\n const sorted = [...albums].sort(byYear);\n\n return (\n <PanelSection title=\"Discography\">\n {GROUPS.map((group) => {\n const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);\n if (groupAlbums.length === 0) return null;\n return (\n <PanelGroup key={group} title={group}>\n <ul>\n {groupAlbums.map((album) => (\n <li key={album.uuid} className=\"grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5\">\n <span className=\"tabular-nums text-[var(--color-text-muted)]\">{album.year ?? \"—\"}</span>\n <span className=\"truncate text-[var(--color-text)]\" title={album.name}>\n {album.name}\n </span>\n </li>\n ))}\n </ul>\n </PanelGroup>\n );\n })}\n </PanelSection>\n );\n}\n","\"use client\";\n\nimport { useState, type MouseEvent } from \"react\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Pagination, PanelSection, Skeleton } from \"@behindthemusictree/ui\";\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport {\n SongDetailedSchema,\n libraryEndpoints,\n songUnplayableReason,\n useTrackList,\n type RenderArtistLink,\n type RenderSongLink,\n type SongDetailed,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PaginatedResponseSchema, usePlaybackQuery } from \"@behindthemusictree/app-kit/transport\";\nimport TrackItem from \"../track-list-sidebar/TrackItem\";\n\nconst SongPageSchema = PaginatedResponseSchema(SongDetailedSchema);\n\nconst SORTS = [\n { ordering: \"title\", label: \"Title\" },\n { ordering: \"-albumYear\", label: \"Year\" },\n] as const;\ntype Ordering = (typeof SORTS)[number][\"ordering\"];\n\ninterface ArtistSongsProps {\n artist: { uuid: string; name: string };\n getBackendBaseUrl: () => string;\n renderArtistLink: RenderArtistLink;\n renderSongLink?: RenderSongLink;\n}\n\nexport default function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }: ArtistSongsProps) {\n const [page, setPage] = useState(1);\n const [ordering, setOrdering] = useState<Ordering>(\"title\");\n const { playNewTrackListFromArtist } = useTrackList<SongDetailed>();\n const { playerTrackObject } = usePlayer();\n const { data, isPending, isError } = usePlaybackQuery({\n getBackendBaseUrl,\n queryKey: [\"referenceSongs\", \"artist\", artist.uuid, ordering, page],\n queryFn: (fetchBound) =>\n fetchBound(libraryEndpoints.reference.songs.list(), true, false, undefined, {\n artist: artist.uuid,\n ordering,\n page,\n }),\n schema: SongPageSchema,\n placeholderData: keepPreviousData,\n context: \"ArtistSongs\",\n });\n\n const play = (startSongUuid?: string) =>\n playNewTrackListFromArtist({ uuid: artist.uuid, name: artist.name }, \"reference\", {\n ordering,\n startSongUuid,\n });\n\n // TrackItem's own play control (`.track-position-play-pause`, a div) plays from whatever list is active; a click on a track that isn't\n // loaded yet must queue this artist's list instead.\n const handleRowClickCapture = (event: MouseEvent, song: SongDetailed) => {\n if (!(event.target instanceof Element) || !event.target.closest(\".track-position-play-pause\")) return;\n if (playerTrackObject?.track.id === song.uuid || songUnplayableReason(song) !== null) return;\n event.stopPropagation();\n void play(song.uuid);\n };\n\n return (\n <PanelSection title=\"Songs\">\n {isPending ? (\n <Skeleton className=\"h-14\" aria-busy=\"true\" />\n ) : isError ? (\n <p className=\"text-red-600\">Could not load songs.</p>\n ) : data.results.length === 0 ? (\n <p className=\"text-[var(--color-text-muted)]\">No songs yet.</p>\n ) : (\n <>\n <div className=\"flex flex-wrap items-center justify-end gap-2 mb-2\">\n <div role=\"group\" aria-label=\"Sort songs by\" className=\"flex gap-1 text-caption\">\n {SORTS.map((sort) => (\n <button\n key={sort.ordering}\n type=\"button\"\n aria-pressed={ordering === sort.ordering}\n onClick={() => {\n setOrdering(sort.ordering);\n setPage(1);\n }}\n className=\"px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white\"\n >\n {sort.label}\n </button>\n ))}\n </div>\n </div>\n <ul className=\"overflow-hidden mb-2 bg-zinc-950 rounded-lg\">\n {data.results.map((song, index) => (\n <li key={song.uuid} onClickCapture={(event) => handleRowClickCapture(event, song)}>\n <TrackItem\n track={song}\n position={(page - 1) * data.pageSize + index + 1}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n </li>\n ))}\n </ul>\n <Pagination currentPage={page} totalPages={data.totalPages} onPageChange={setPage} />\n </>\n )}\n </PanelSection>\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport { useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport TrackPositionPlayPause from \"../TrackPositionPlayPause\";\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { isSong, songUnplayableReason } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { MusicBrainzRecordingLink } from \"../MusicBrainzRecordingLink\";\nimport type { RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { ArtistNames, RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport interface TrackItemProps<T extends TrackBase> {\n track: T;\n position: number;\n renderDuration?: (track: T) => ReactNode;\n renderActions?: (track: T) => ReactNode;\n /** When set, artist names render through it (e.g. a router `Link`). */\n renderArtistLink?: RenderArtistLink;\n /** When set, a song title renders through it (e.g. opens the song panel) instead of linking to MusicBrainz. */\n renderSongLink?: RenderSongLink;\n}\n\nexport default function TrackItem<T extends TrackBase>({\n track,\n position,\n renderDuration,\n renderActions,\n renderArtistLink,\n renderSongLink,\n}: TrackItemProps<T>) {\n const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = usePlayer();\n const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = useTrackList<T>();\n const scope = trackList?.origin?.scope ?? null;\n const isCurrentTrack = playerTrackObject?.track.id === track.uuid;\n const hasPlaybackError = isCurrentTrack && !!playerTrackObject?.loadError;\n const isUnplayable =\n hasPlaybackError ||\n runtimeUnplayableTrackIds?.has(track.uuid) === true ||\n (isSong(track) && songUnplayableReason(track) !== null);\n\n const handlePlayPauseClick = (event: React.MouseEvent) => {\n event.stopPropagation();\n if (isCurrentTrack) {\n handlePlayPauseAction();\n } else if (scope != null) {\n toTrackAtPosition(position);\n loadTrackForPlayer(track.uuid);\n }\n };\n\n return (\n <div\n className={`track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? \"opacity-50\" : \"hover:bg-[var(--color-surface-muted)] group\"}`}\n >\n {isUnplayable ? (\n <div\n className=\"flex items-center justify-center text-lg w-16\"\n style={{ minWidth: \"4rem\", maxWidth: \"4rem\" }}\n aria-disabled=\"true\"\n >\n {position}\n </div>\n ) : (\n <TrackPositionPlayPause\n position={position}\n uuid={track.uuid}\n handlePlayPauseClick={handlePlayPauseClick}\n isSelected={selectedTrack?.uuid === track.uuid}\n />\n )}\n <div className=\"title-artist-container flex flex-col items-start justify-center min-w-0 flex-1\">\n <div className=\"flex max-w-full items-center gap-2\">\n <div className=\"title text-lg font-bold text-[var(--color-text)] max-w-full truncate\">\n {renderSongLink ? (\n renderSongLink(track)\n ) : isSong(track) ? (\n <MusicBrainzRecordingLink song={track} className=\"hover:underline focus-visible:underline\">\n {track.title}\n </MusicBrainzRecordingLink>\n ) : (\n track.title\n )}\n </div>\n </div>\n {track.artists && track.artists.length > 0 ? (\n <div className=\"artist text-base max-w-full truncate text-[var(--color-text-muted)]\">\n <ArtistNames artists={track.artists} renderArtistLink={renderArtistLink} />\n </div>\n ) : (\n \"\"\n )}\n </div>\n <div className=\"genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0\">\n {track.genre ? (\n <div className=\"genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold\">{track.genre.name}</div>\n ) : (\n \"\"\n )}\n </div>\n {renderDuration && (\n <div\n className=\"duration flex text-base w-16 items-center justify-center\"\n style={{ minWidth: \"4rem\", maxWidth: \"4rem\" }}\n >\n {renderDuration(track)}\n </div>\n )}\n {renderActions && (\n <div className=\"edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer\">\n {renderActions(track)}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { FaPlay, FaPause } from \"react-icons/fa\";\n\nimport { usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport { PlayStates } from \"@behindthemusictree/app-kit/player\";\n\nexport interface TrackPositionPlayPauseProps {\n position: number;\n uuid: string;\n handlePlayPauseClick: (event: React.MouseEvent) => void;\n isSelected?: boolean;\n}\n\nexport default function TrackPositionPlayPause({\n position,\n uuid,\n handlePlayPauseClick,\n isSelected = false,\n}: TrackPositionPlayPauseProps) {\n const { playerTrackObject, playbackConfirmedTrackId, playState, isLoading: isPlayerLoading } = usePlayer();\n const isThisTrack = playerTrackObject?.track.id === uuid;\n const isConfirmedPlayable = playbackConfirmedTrackId === uuid;\n const isAwaitingPlayback =\n (isSelected || isThisTrack) &&\n !isConfirmedPlayable &&\n !(isThisTrack && playerTrackObject?.loadError) &&\n (!isThisTrack || isPlayerLoading || playState === PlayStates.LOADING || playState === PlayStates.PLAYING);\n const isPlaying = isThisTrack && isConfirmedPlayable && playState === PlayStates.PLAYING;\n const isPaused = isThisTrack && isConfirmedPlayable && playState === PlayStates.PAUSED;\n const isCurrentTrackActive = isPlaying || isPaused;\n\n return (\n <div\n className=\"track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer\"\n style={{ minWidth: \"4rem\", maxWidth: \"4rem\" }}\n onClick={handlePlayPauseClick}\n >\n <div className=\"track-position-play-pause__status group-hover:hidden flex items-center justify-center\">\n {isAwaitingPlayback ? (\n <span className=\"track-position-play-pause__spinner\" role=\"status\" aria-label=\"Loading track\" />\n ) : isCurrentTrackActive ? (\n <span\n className=\"track-position-play-pause__bars\"\n data-playing={isPlaying}\n role=\"img\"\n aria-label={isPlaying ? \"Playing\" : \"Paused\"}\n >\n <span className=\"track-position-play-pause__bar\" />\n <span className=\"track-position-play-pause__bar\" />\n <span className=\"track-position-play-pause__bar\" />\n </span>\n ) : (\n position\n )}\n </div>\n <div\n className={`hidden group-hover:flex items-center justify-center ${\n isCurrentTrackActive ? \"\" : \"absolute inset-0\"\n }`}\n aria-hidden=\"true\"\n >\n {isAwaitingPlayback ? (\n <span className=\"track-position-play-pause__spinner\" />\n ) : isPlaying ? (\n <FaPause />\n ) : (\n <FaPlay />\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { Skeleton } from \"@behindthemusictree/ui\";\nimport {\n useSong,\n type CriteriaMinimum,\n type CriteriaPlaylistSimple,\n type RenderArtistLink,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport type { GetGenreTreeShareUrl } from \"../share\";\nimport SongPanelContent from \"./SongPanelContent\";\nimport type { OverlayPanel } from \"../overlayPanel\";\n\n/** How the song's genre is opened: through the loaded tree's playlists, or by the genre alone for a host without a tree. */\nexport type SongGenreNavigation =\n | {\n /** Root-to-leaf playlists of a genre in the loaded tree; empty when the tree doesn't hold it. */\n getGenrePath: (genre: CriteriaMinimum) => CriteriaPlaylistSimple[];\n onSelectGenrePlaylist: (genrePlaylist: CriteriaPlaylistSimple) => void;\n onSelectGenre?: never;\n }\n | {\n onSelectGenre: (genre: CriteriaMinimum) => void;\n getGenrePath?: never;\n onSelectGenrePlaylist?: never;\n };\n\nexport type SongPanelOptions = {\n uuid: string | null;\n scope: Scope;\n getBackendBaseUrl: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n renderArtistLink: RenderArtistLink;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n onClose: () => void;\n} & SongGenreNavigation;\n\n/** The song detail overlay panel for `uuid`, or undefined when no song is set. */\nexport function useSongPanel({\n uuid,\n scope,\n getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n expanded,\n onExpandedChange,\n onClose,\n ...navigation\n}: SongPanelOptions): OverlayPanel | undefined {\n const result = useSong(uuid, getBackendBaseUrl);\n\n const panel = { expanded, onExpandedChange, onClose };\n switch (result.status) {\n case \"idle\":\n return undefined;\n case \"loading\":\n return {\n ...panel,\n title: \"Song\",\n content: (\n <div aria-busy=\"true\" className=\"flex flex-col gap-2.5\">\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-4 w-24\" />\n </div>\n ),\n };\n case \"not-found\":\n return {\n ...panel,\n title: \"Song not found\",\n content: <p className=\"text-[var(--color-text-muted)]\">This song does not exist.</p>,\n };\n case \"error\":\n return {\n ...panel,\n title: \"Song\",\n content: <p className=\"text-red-600\">Could not load this song.</p>,\n };\n case \"success\": {\n const { song } = result;\n const shareUrl = getShareUrl?.({ kind: \"song\", uuid: song.uuid, name: song.title, scope });\n return {\n ...panel,\n title: song.title,\n content: (\n <SongPanelContent\n song={song}\n scope={scope}\n getBackendBaseUrl={getBackendBaseUrl}\n shareUrl={shareUrl ?? undefined}\n renderArtistLink={renderArtistLink}\n {...(navigation.getGenrePath\n ? {\n genrePath: song.genre ? navigation.getGenrePath(song.genre) : [],\n onSelectGenrePlaylist: navigation.onSelectGenrePlaylist,\n }\n : { onSelectGenre: navigation.onSelectGenre })}\n />\n ),\n };\n }\n }\n}\n","\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\nimport { Pause, Play } from \"lucide-react\";\nimport { ActionBand, ActionButton, FieldList, PANEL_LABEL_CLASS, PanelBleed, PanelSection, Skeleton } from \"@behindthemusictree/ui\";\nimport { PlayStates, usePlayer } from \"@behindthemusictree/app-kit/player\";\nimport {\n ArtistNames,\n musicBrainzRecordingUrl,\n songUnplayableReason,\n useSongHistory,\n useTrackList,\n type CriteriaMinimum,\n type CriteriaPlaylistSimple,\n type RenderArtistLink,\n type SongDetailed,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport ShareActionButton from \"../ShareActionButton\";\nimport type { GenreTreeShareTarget } from \"../share\";\n\nexport type SongPanelContentProps = {\n song: SongDetailed;\n scope: Scope;\n getBackendBaseUrl: () => string;\n shareUrl?: string;\n renderArtistLink: RenderArtistLink;\n} & (\n | {\n /** Root-to-leaf playlists of the song's genre in the loaded tree; empty when the tree doesn't hold it. */\n genrePath: CriteriaPlaylistSimple[];\n onSelectGenrePlaylist: (genrePlaylist: CriteriaPlaylistSimple) => void;\n onSelectGenre?: never;\n }\n | {\n /** The genre alone opens, for a host without a tree. */\n onSelectGenre: (genre: CriteriaMinimum) => void;\n genrePath?: never;\n onSelectGenrePlaylist?: never;\n }\n);\n\nconst numberFormat = new Intl.NumberFormat(\"en\");\nconst dateFormat = new Intl.DateTimeFormat(\"en\", { dateStyle: \"medium\" });\n\nconst externalLink = \"text-[var(--color-primary)] hover:underline focus-visible:underline\";\n\nfunction SongHistory({ uuid, getBackendBaseUrl }: { uuid: string; getBackendBaseUrl: () => string }) {\n const [open, setOpen] = useState(false);\n const history = useSongHistory(uuid, getBackendBaseUrl, open);\n let body: ReactNode = null;\n if (history.status === \"loading\") body = <Skeleton className=\"h-10\" aria-busy=\"true\" />;\n else if (history.status === \"error\") body = <p className=\"text-red-600\">Could not load the history.</p>;\n else if (history.status === \"success\")\n body =\n history.entries.length === 0 ? (\n <p className=\"text-[var(--color-text-muted)]\">No changes yet.</p>\n ) : (\n <ul className=\"divide-y divide-[var(--color-border)]\">\n {history.entries.map((entry) => (\n <li key={entry.uuid} className=\"py-1.5 text-body\">\n <span className=\"font-medium\">{entry.action}</span>\n {entry.oldValue !== null || entry.newValue !== null ? (\n <span className=\"text-[var(--color-text-muted)]\">\n {\" \"}\n — {entry.oldValue ?? \"none\"} → {entry.newValue ?? \"none\"}\n </span>\n ) : null}\n <span className=\"block text-caption text-[var(--color-text-muted)]\">\n {entry.actorPseudo ?? \"Anonymous\"} · {dateFormat.format(new Date(entry.createdOn))}\n </span>\n </li>\n ))}\n </ul>\n );\n\n return (\n <PanelBleed padded className=\"border-t border-[var(--color-border)]\">\n <details onToggle={(event) => setOpen(event.currentTarget.open)} className=\"pb-2.5\">\n <summary className={`mt-2.5 cursor-pointer ${PANEL_LABEL_CLASS}`}>\n History\n </summary>\n <div className=\"mt-1.5\">{body}</div>\n </details>\n </PanelBleed>\n );\n}\n\nexport default function SongPanelContent(props: SongPanelContentProps) {\n const { song, scope, getBackendBaseUrl, shareUrl, renderArtistLink } = props;\n const { playNewTrackListFromTrackUuid } = useTrackList<SongDetailed>();\n const { playerTrackObject, playState, handlePlayPauseAction } = usePlayer();\n const unplayableReason = songUnplayableReason(song);\n const isCurrent = playerTrackObject?.track.id === song.uuid;\n const isPlaying = isCurrent && playState === PlayStates.PLAYING;\n const shareTarget: GenreTreeShareTarget = { kind: \"song\", uuid: song.uuid, name: song.title, scope };\n const musicBrainzUrl = musicBrainzRecordingUrl(song);\n\n const fields: { label: string; value: ReactNode }[] = [];\n if (song.genre) {\n const path = props.genrePath && props.genrePath.length > 0 ? props.genrePath : null;\n const { onSelectGenre } = props;\n const genre = song.genre;\n fields.push({\n label: \"Genre\",\n value: onSelectGenre ? (\n <button type=\"button\" onClick={() => onSelectGenre(genre)} className=\"hover:underline\">\n {genre.name}\n </button>\n ) : path ? (\n <span className=\"flex flex-wrap items-center gap-x-1\">\n {path.map((genrePlaylist, index) => (\n <span key={genrePlaylist.uuid}>\n {index > 0 && <span aria-hidden=\"true\">› </span>}\n <button type=\"button\" onClick={() => props.onSelectGenrePlaylist?.(genrePlaylist)} className=\"hover:underline\">\n {genrePlaylist.name}\n </button>\n </span>\n ))}\n </span>\n ) : (\n song.genre.name\n ),\n });\n } else {\n fields.push({ label: \"Genre\", value: <span className=\"text-[var(--color-text-muted)]\">No genre</span> });\n }\n if (song.firstReleaseYear) fields.push({ label: \"First released\", value: song.firstReleaseYear });\n const viewCount = song.youtubeVideo?.viewCount;\n if (viewCount !== null && viewCount !== undefined)\n fields.push({ label: \"YouTube views\", value: numberFormat.format(viewCount) });\n fields.push({ label: \"Plays\", value: numberFormat.format(song.playCount) });\n const links: ReactNode[] = [];\n if (musicBrainzUrl)\n links.push(\n <a key=\"mb\" href={musicBrainzUrl} target=\"_blank\" rel=\"noopener noreferrer\" className={externalLink}>\n MusicBrainz\n </a>,\n );\n if (song.youtubeVideo)\n links.push(\n <a\n key=\"yt\"\n href={`https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={externalLink}\n >\n YouTube\n </a>,\n );\n if (links.length > 0)\n fields.push({\n label: \"Links\",\n value: <span className=\"flex gap-3\">{links}</span>,\n });\n\n return (\n <>\n <PanelBleed>\n <ActionBand>\n <ActionButton\n icon={isPlaying ? <Pause aria-hidden=\"true\" className=\"w-5 h-5\" /> : <Play aria-hidden=\"true\" className=\"w-5 h-5\" />}\n label={isPlaying ? \"Pause\" : \"Play\"}\n disabled={!!unplayableReason}\n title={unplayableReason ?? undefined}\n onClick={() => (isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope))}\n />\n {shareUrl && <ShareActionButton target={shareTarget} url={shareUrl} />}\n </ActionBand>\n </PanelBleed>\n {song.artists && song.artists.length > 0 && (\n <p className=\"text-[var(--color-text-muted)]\">\n <ArtistNames artists={song.artists} renderArtistLink={renderArtistLink} />\n </p>\n )}\n <FieldList items={fields} />\n {song.essentialGenres && song.essentialGenres.length > 0 && (\n <PanelSection title=\"Essential in\">\n <ul>\n {song.essentialGenres.map((genre) => (\n <li key={genre.uuid} className=\"py-0.5\">\n {genre.name}\n </li>\n ))}\n </ul>\n </PanelSection>\n )}\n <SongHistory uuid={song.uuid} getBackendBaseUrl={getBackendBaseUrl} />\n </>\n );\n}\n","\"use client\";\n\nimport type { RenderArtistLink, RenderPlaceLink, RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useArtistPanel } from \"./artist/useArtistPanel\";\nimport { useSongPanel, type SongGenreNavigation } from \"./song/useSongPanel\";\nimport type { GetGenreTreeShareUrl } from \"./share\";\nimport type { OverlayPanel } from \"./overlayPanel\";\n\nexport interface EntityPanelState {\n uuid: string | null;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n onClose: () => void;\n}\n\nexport type EntityPanelOptions = {\n scope: Scope;\n getBackendBaseUrl: () => string;\n /** Artist requests go here when the host serves them from elsewhere; defaults to `getBackendBaseUrl`. */\n getArtistBackendBaseUrl?: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n renderArtistLink: RenderArtistLink;\n renderSongLink: RenderSongLink;\n renderPlaceLink?: RenderPlaceLink;\n song: EntityPanelState;\n artist: EntityPanelState;\n} & SongGenreNavigation;\n\n/** The song or artist detail overlay panel; a song takes precedence over an artist, undefined when neither is set. */\nexport function useEntityPanel({\n scope,\n getBackendBaseUrl,\n getArtistBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n song,\n artist,\n ...navigation\n}: EntityPanelOptions): OverlayPanel | undefined {\n const songPanel = useSongPanel({\n ...song,\n scope,\n getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n ...navigation,\n } as Parameters<typeof useSongPanel>[0]);\n const artistPanel = useArtistPanel({\n ...artist,\n scope,\n getBackendBaseUrl: getArtistBackendBaseUrl ?? getBackendBaseUrl,\n getShareUrl,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n });\n return songPanel ?? artistPanel;\n}\n","\"use client\";\n\nimport { MdMusicNote, MdVisibility } from \"react-icons/md\";\nimport { SegmentedControl } from \"@behindthemusictree/ui\";\n\nimport type { GenreTreeSizeMetric } from \"./playlist-tree/size-metric\";\n\nexport function SizeMetricToggle({\n value,\n onChange,\n}: {\n value: GenreTreeSizeMetric;\n onChange: (value: GenreTreeSizeMetric) => void;\n}) {\n return (\n <SegmentedControl\n variant=\"floating\"\n aria-label=\"Size nodes by\"\n value={value}\n onChange={onChange}\n options={[\n { value: \"songs\", label: <MdMusicNote size={18} aria-hidden />, \"aria-label\": \"Size by songs\", title: \"Node size by song count\" },\n { value: \"views\", label: <MdVisibility size={18} aria-hidden />, \"aria-label\": \"Size by views\", title: \"Node size by song views\" },\n ]}\n />\n );\n}\n","export * from \"./GenreTreeView\";\nexport type { GenreTreeShareTarget, GetGenreTreeShareUrl } from \"./share\";\nexport type { ParentChange } from \"./ChangeParentPopup\";\nexport type { GenreDetailSlots } from \"./GenreDetailExtras\";\nexport { GenreDetailPanel } from \"./GenreDetailPanel\";\nexport type { GenreDetailPanelProps } from \"./GenreDetailPanel\";\nexport { GenreInfoPanelBody, GenreNodeActionBand } from \"./GenreInfoPanelBody\";\nexport type { GenreInfoPanelBodyProps, PlayableGenrePlaylist } from \"./GenreInfoPanelBody\";\nexport { useGenrePlaylistPlayback } from \"./playlist-tree/useGenrePlaylistPlayback\";\nexport type { GenrePlaylistPlayback, UseGenrePlaylistPlaybackOptions } from \"./playlist-tree/useGenrePlaylistPlayback\";\nexport type { GenrePlaylistTracksSlots } from \"./GenrePlaylistTracks\";\nexport { default as GenrePlaylistTreePerRoot } from \"./playlist-tree/TreePerRoot\";\nexport type { GenrePlaylistTreePerRootProps } from \"./playlist-tree/TreePerRoot\";\nexport { default as GenreSearch } from \"./GenreSearch\";\nexport type { GenreSearchProps, GenreSearchExtraGroup } from \"./GenreSearch\";\nexport * from \"./search\";\nexport {\n GenreTreeSkeleton,\n GenreTreeWheelSkeleton,\n GenreTreeViewSkeleton,\n GenreTreeOutlineSkeleton,\n} from \"@behindthemusictree/genre-tree-view\";\nexport type { GenreTreeAction, GenreTreeViewport, GenreTreeViewSkeletonProps } from \"@behindthemusictree/genre-tree-view\";\nexport { default as TrackListSidebar } from \"./track-list-sidebar/TrackListSidebar\";\nexport type { TrackListSidebarProps } from \"./track-list-sidebar/TrackListSidebar\";\nexport { default as PlayerPanel } from \"./PlayerPanel\";\nexport type { PlayerPanelProps } from \"./PlayerPanel\";\nexport { default as TrackItem } from \"./track-list-sidebar/TrackItem\";\nexport type { TrackItemProps } from \"./track-list-sidebar/TrackItem\";\nexport { default as TrackPositionPlayPause } from \"./TrackPositionPlayPause\";\nexport type { TrackPositionPlayPauseProps } from \"./TrackPositionPlayPause\";\nexport { default as Rating } from \"./Rating\";\nexport type { RatingProps } from \"./Rating\";\n\nexport type { GenreSearchGroupsProps } from \"./GenreTreeSearch\";\nexport { useEntityPanel } from \"./useEntityPanel\";\nexport type { EntityPanelOptions, EntityPanelState } from \"./useEntityPanel\";\nexport { EntityDetailPanel } from \"./EntityDetailPanel\";\nexport type { EntityDetailPanelProps } from \"./EntityDetailPanel\";\nexport type { SongGenreNavigation } from \"./song/useSongPanel\";\n","\"use client\";\n\nimport { ReactNode, useEffect, useLayoutEffect, useRef } from \"react\";\nimport { ListMusic } from \"lucide-react\";\n\nimport TrackItem from \"./TrackItem\";\nimport { useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { TrackListOriginType } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { TrackBase } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { RenderArtistLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\n\nconst useBrowserLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\nexport interface TrackListSidebarProps<T extends TrackBase> {\n className?: string;\n renderDuration?: (track: T) => ReactNode;\n renderActions?: (track: T) => ReactNode;\n layout?: \"fixed\" | \"inline\";\n isCollapsed?: boolean;\n onExpand?: () => void;\n onMinimize?: () => void;\n /** When set, artist names render through it (e.g. a router `Link`). */\n renderArtistLink?: RenderArtistLink;\n /** When set, song titles render through it (e.g. open the song panel). */\n renderSongLink?: RenderSongLink;\n}\n\nexport default function TrackListSidebar<T extends TrackBase>({\n className = \"\",\n renderDuration,\n renderActions,\n layout = \"fixed\",\n isCollapsed = false,\n onExpand,\n onMinimize,\n renderArtistLink,\n renderSongLink,\n}: TrackListSidebarProps<T>) {\n const { trackList, loadMore, autoAdvanceScrollRequest } = useTrackList<T>();\n const trackNoun = useTrackNoun();\n const trackListRef = useRef<HTMLUListElement>(null);\n const previousOriginRef = useRef(trackList?.origin ?? null);\n const handledAutoAdvanceRequestIdRef = useRef<number | null>(null);\n const shouldFollowPlaybackRef = useRef(true);\n const programmaticScrollTopRef = useRef<number | null>(null);\n const userScrollIntentRef = useRef(false);\n const userScrollIntentTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const loadMoreSentinelRef = useRef<HTMLLIElement>(null);\n const hasMore = !!trackList && trackList.nextPage !== null;\n\n useEffect(() => {\n const sentinel = loadMoreSentinelRef.current;\n if (!hasMore || !sentinel) return;\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n loadMore().catch((error) => console.error(\"Failed to load more tracks:\", error));\n }\n });\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasMore, loadMore]);\n\n useBrowserLayoutEffect(() => {\n const origin = trackList?.origin ?? null;\n if (previousOriginRef.current === origin) return;\n previousOriginRef.current = origin;\n handledAutoAdvanceRequestIdRef.current = null;\n shouldFollowPlaybackRef.current = true;\n programmaticScrollTopRef.current = null;\n if (trackListRef.current) trackListRef.current.scrollTop = 0;\n }, [trackList?.origin]);\n\n useEffect(() => {\n const list = trackListRef.current;\n if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;\n }, [isCollapsed]);\n\n useEffect(\n () => () => {\n if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);\n },\n [],\n );\n\n useBrowserLayoutEffect(() => {\n if (\n !autoAdvanceScrollRequest ||\n handledAutoAdvanceRequestIdRef.current === autoAdvanceScrollRequest.id\n ) {\n return;\n }\n if (isCollapsed) return;\n\n const list = trackListRef.current;\n if (!list) return;\n if (list.scrollTop <= 1) shouldFollowPlaybackRef.current = true;\n if (!shouldFollowPlaybackRef.current) {\n handledAutoAdvanceRequestIdRef.current = autoAdvanceScrollRequest.id;\n return;\n }\n\n const row = Array.from(list.querySelectorAll<HTMLElement>(\"[data-track-uuid]\")).find(\n (element) => element.dataset.trackUuid === autoAdvanceScrollRequest.trackUuid,\n );\n if (!row) return;\n handledAutoAdvanceRequestIdRef.current = autoAdvanceScrollRequest.id;\n\n const rowTop = row.getBoundingClientRect().top - list.getBoundingClientRect().top;\n const targetScrollTop = list.scrollTop + rowTop;\n programmaticScrollTopRef.current = targetScrollTop;\n list.scrollTop = targetScrollTop;\n programmaticScrollTopRef.current = list.scrollTop;\n }, [autoAdvanceScrollRequest, isCollapsed, trackList]);\n\n const markUserScrollIntent = () => {\n userScrollIntentRef.current = true;\n if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);\n userScrollIntentTimerRef.current = setTimeout(() => {\n userScrollIntentRef.current = false;\n userScrollIntentTimerRef.current = null;\n }, 250);\n };\n\n const handleTrackListScroll = (event: React.UIEvent<HTMLUListElement>) => {\n const list = event.currentTarget;\n if (userScrollIntentRef.current) {\n userScrollIntentRef.current = false;\n if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);\n userScrollIntentTimerRef.current = null;\n programmaticScrollTopRef.current = null;\n shouldFollowPlaybackRef.current = list.scrollTop <= 1;\n return;\n }\n\n const programmaticScrollTop = programmaticScrollTopRef.current;\n if (programmaticScrollTop !== null) {\n if (Math.abs(list.scrollTop - programmaticScrollTop) <= 1) programmaticScrollTopRef.current = null;\n return;\n }\n };\n const positionClasses =\n layout === \"inline\"\n ? \"relative w-full flex h-full flex-col\"\n : \"fixed right-0 w-[50rem] flex flex-col\";\n\n return trackList ? (\n <div\n data-theme=\"dark\"\n className={`track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className}`}\n style={layout === \"fixed\" ? { top: \"63.5px\", maxHeight: \"calc(100vh - 63.5px - 79px)\" } : undefined}\n >\n <div className=\"header flex h-16 items-center px-4 py-2 text-[var(--color-text)]\">\n <div className=\"min-w-0 flex flex-1 flex-col justify-center\">\n <div className=\"origin flex text-xl\">\n <div className=\"from h-auto flex flex-col justify-center items-center mr-2\">From</div>\n <div className=\"name-container flex flex-col justify-center items-center text-[var(--color-text)] font-bold pr-2 max-w-[27.5rem]\">\n <div className=\"name max-w-full truncate\">{trackList.origin.label}</div>\n </div>\n </div>\n <div className=\"info flex items-center text-body text-[var(--color-text-muted)]\">\n {trackList.origin.type === TrackListOriginType.GENRE_PLAYLIST\n ? \"Genre • \"\n : trackList.origin.type === TrackListOriginType.ARTIST\n ? \"Artist • \"\n : `${trackNoun.singular} playlist • `}\n {`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`}\n </div>\n </div>\n {((isCollapsed && onExpand) || (!isCollapsed && onMinimize)) && (\n <button\n type=\"button\"\n aria-label={isCollapsed ? \"Show tracks\" : \"Hide tracks\"}\n title={isCollapsed ? \"Show tracks\" : \"Hide tracks\"}\n aria-expanded={!isCollapsed}\n className={`ml-2 flex h-8 w-8 shrink-0 items-center justify-center rounded-md hover:bg-[var(--color-surface-muted)] ${isCollapsed ? \"text-[var(--color-text-muted)]\" : \"text-white\"}`}\n onClick={isCollapsed ? onExpand : onMinimize}\n >\n <ListMusic aria-hidden=\"true\" className=\"h-5 w-5\" />\n </button>\n )}\n </div>\n {!isCollapsed && (\n <ul\n ref={trackListRef}\n onScroll={handleTrackListScroll}\n onWheel={markUserScrollIntent}\n onTouchMove={markUserScrollIntent}\n onPointerDown={markUserScrollIntent}\n className={\n layout === \"inline\"\n ? \"track-list flex-1 min-h-0 overflow-auto list-none p-0 m-0\"\n : \"track-list flex-1 min-h-0 overflow-auto list-none p-0 m-0\"\n }\n >\n {trackList.tracks.map((track, index) => (\n <li key={track.uuid} data-track-uuid={track.uuid}>\n <TrackItem\n track={track}\n position={index + 1}\n renderDuration={renderDuration}\n renderActions={renderActions}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n </li>\n ))}\n {hasMore && <li ref={loadMoreSentinelRef} aria-hidden=\"true\" className=\"h-px\" />}\n </ul>\n )}\n </div>\n ) : null;\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { X } from \"lucide-react\";\nimport { twMerge } from \"tailwind-merge\";\nimport {\n usePlayer,\n PlayerVideoSurface,\n} from \"@behindthemusictree/app-kit/player\";\nimport {\n useTrackListSidebarVisibility,\n type RenderArtistLink,\n type RenderSongLink,\n} from \"@behindthemusictree/app-kit/genre-tree\";\nimport { IconButton, PanelEdgeTab } from \"@behindthemusictree/ui\";\nimport PlayerControls from \"./PlayerControls\";\nimport TrackListSidebar from \"./track-list-sidebar/TrackListSidebar\";\n\nexport interface PlayerPanelProps {\n className?: string;\n /** Hidden via CSS, never unmounted, so the video keeps playing while the host hides the panel. */\n isVisible?: boolean;\n /** Controlled extended state; uncontrolled when omitted. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** Width once extended, e.g. to stop short of a left-hand detail panel. */\n extendedWidth?: string;\n renderArtistLink?: RenderArtistLink;\n /** When set, song titles in the tracklist render through it (e.g. open the song panel). */\n renderSongLink?: RenderSongLink;\n}\n\nconst PANEL_ID = \"player-panel\";\n\n// Spans the center and right columns.\nconst DEFAULT_EXTENDED_WIDTH =\n \"calc(100vw - var(--layout-center-left) - var(--layout-gutter))\";\n\nexport default function PlayerPanel({\n className,\n isVisible = true,\n expanded,\n onExpandedChange,\n extendedWidth = DEFAULT_EXTENDED_WIDTH,\n renderArtistLink,\n renderSongLink,\n}: PlayerPanelProps) {\n const { playerTrackObject, retryPlayback, stop } = usePlayer();\n const { toggleTrackListSidebar, isTrackListSidebarVisible } =\n useTrackListSidebarVisibility();\n const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = useState(\"\");\n const loadedTrackTitle = playerTrackObject?.track.title;\n useEffect(() => {\n if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);\n }, [loadedTrackTitle]);\n const [uncontrolledExtended, setUncontrolledExtended] = useState(false);\n const isExtendRequested = expanded ?? uncontrolledExtended;\n const setIsExtendRequested = (next: boolean) => {\n setUncontrolledExtended(next);\n onExpandedChange?.(next);\n };\n const isExtended = isExtendRequested && isTrackListSidebarVisible;\n const hideSongList = () => {\n setIsExtendRequested(false);\n if (isTrackListSidebarVisible) toggleTrackListSidebar();\n };\n\n const tabEdge =\n isTrackListSidebarVisible && isExtended\n ? {\n label: \"Shrink player panel\",\n onClick: () => setIsExtendRequested(false),\n expanded: true,\n }\n : null;\n const tabCenter =\n isTrackListSidebarVisible && !isExtended\n ? {\n label: \"Extend player panel\",\n onClick: () => setIsExtendRequested(true),\n expanded: false,\n }\n : null;\n\n return (\n <div\n id={PANEL_ID}\n className={twMerge(\n \"fixed right-[var(--layout-gutter)] top-[var(--layout-band-top)] z-40 max-h-[calc(100vh-var(--layout-band-top)-3.5rem)]\",\n !isExtended && \"w-[var(--layout-right-w)]\",\n isTrackListSidebarVisible &&\n \"h-[calc(100vh-var(--layout-band-top)-3.5rem)]\",\n !isVisible && \"hidden\",\n className,\n )}\n style={isExtended ? { width: extendedWidth } : undefined}\n >\n <PanelEdgeTab\n side=\"right\"\n edge={tabEdge}\n center={tabCenter}\n controls={PANEL_ID}\n className=\"absolute right-full top-1/2 -translate-y-1/2\"\n />\n <div\n className={twMerge(\n \"flex h-full max-h-[inherit] overflow-hidden rounded-[var(--radius-panel,1rem)] bg-zinc-950 text-zinc-100 shadow-[0_1px_2px_rgba(0,0,0,0.5),0_2px_6px_2px_rgba(0,0,0,0.3)]\",\n isExtended ? \"flex-row\" : \"flex-col\",\n )}\n >\n <div className=\"flex w-[var(--layout-right-w)] shrink-0 flex-col\">\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2\">\n <span className=\"min-w-0 truncate text-sm font-semibold\">\n {loadedTrackTitle || lastLoadedTrackTitle}\n </span>\n {playerTrackObject && (\n <IconButton aria-label=\"Close player\" onClick={stop}>\n <X aria-hidden=\"true\" className=\"h-4 w-4\" />\n </IconButton>\n )}\n </div>\n <div className=\"relative w-full shrink-0\">\n <PlayerVideoSurface className=\"aspect-video w-full bg-black\" />\n {playerTrackObject?.loadError && (\n <span className=\"absolute bottom-2 left-2 right-2 text-xs text-red-400\">\n {playerTrackObject.loadError}\n <button type=\"button\" className=\"ml-2 underline\" onClick={() => { void retryPlayback(); }}>Retry</button>\n </span>\n )}\n </div>\n <PlayerControls />\n </div>\n <TrackListSidebar\n layout=\"inline\"\n isCollapsed={!isTrackListSidebarVisible}\n onExpand={toggleTrackListSidebar}\n onMinimize={hideSongList}\n className={twMerge(\n \"min-h-0 min-w-0 flex-1\",\n isExtended && \"border-l border-zinc-800\",\n )}\n renderArtistLink={renderArtistLink}\n renderSongLink={renderSongLink}\n />\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { Pause, Play, SkipBack, SkipForward, Volume2, VolumeX } from \"lucide-react\";\nimport { formatTime, useTrackList } from \"@behindthemusictree/app-kit/genre-tree\";\nimport { PlayStates, useCurrentTime, usePlayer } from \"@behindthemusictree/app-kit/player\";\n\nexport default function PlayerControls() {\n const {\n duration,\n handlePlayPauseAction,\n isLoading,\n playState,\n playerTrackObject,\n seekTo,\n setVolume,\n volume,\n } = usePlayer();\n const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = useTrackList();\n const currentTime = useCurrentTime();\n const isBusy = isLoading || playState === PlayStates.LOADING;\n const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;\n const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;\n const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;\n const isPlaying = playState === PlayStates.PLAYING;\n\n return (\n <section\n aria-label=\"Player controls\"\n className=\"player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200\"\n >\n <div className=\"flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400\">\n <span aria-label=\"Elapsed time\">{formatTime(safeCurrentTime)}</span>\n <input\n aria-label=\"Seek\"\n className=\"h-1 min-w-0 flex-1 cursor-pointer accent-white disabled:cursor-not-allowed disabled:opacity-40\"\n type=\"range\"\n min={0}\n max={safeDuration}\n step={0.1}\n value={safeCurrentTime}\n disabled={!isReady || safeDuration <= 0}\n onChange={(event) => seekTo(Number(event.currentTarget.value))}\n />\n <span aria-label=\"Duration\">{formatTime(safeDuration)}</span>\n </div>\n\n <div className=\"grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3\">\n <div className=\"col-start-2 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n aria-label=\"Previous track\"\n title=\"Previous track\"\n disabled={!isReady || !hasPreviousTrack}\n onClick={playPreviousTrack}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <SkipBack aria-hidden=\"true\" className=\"h-4 w-4\" />\n </button>\n <button\n type=\"button\"\n aria-label={isPlaying ? \"Pause\" : \"Play\"}\n title={isPlaying ? \"Pause\" : \"Play\"}\n disabled={!isReady}\n onClick={handlePlayPauseAction}\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-white text-zinc-950 hover:bg-zinc-200 disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {isPlaying ? (\n <Pause aria-hidden=\"true\" className=\"h-4 w-4\" fill=\"currentColor\" />\n ) : (\n <Play aria-hidden=\"true\" className=\"h-4 w-4\" fill=\"currentColor\" />\n )}\n </button>\n <button\n type=\"button\"\n aria-label=\"Next track\"\n title=\"Next track\"\n disabled={!isReady || !hasNextTrack}\n onClick={playNextTrack}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <SkipForward aria-hidden=\"true\" className=\"h-4 w-4\" />\n </button>\n </div>\n\n <label className=\"col-start-3 flex w-[4.2rem] shrink-0 items-center gap-[0.35rem] justify-self-end text-zinc-400 sm:w-[4.9rem]\">\n {volume === 0 ? (\n <VolumeX aria-hidden=\"true\" className=\"h-[0.7rem] w-[0.7rem] shrink-0\" />\n ) : (\n <Volume2 aria-hidden=\"true\" className=\"h-[0.7rem] w-[0.7rem] shrink-0\" />\n )}\n <span className=\"sr-only\">Volume</span>\n <input\n aria-label=\"Volume\"\n className=\"h-[3px] min-w-0 flex-1 cursor-pointer accent-white disabled:cursor-not-allowed disabled:opacity-40\"\n type=\"range\"\n min={0}\n max={100}\n step={1}\n value={volume}\n disabled={!isReady}\n onChange={(event) => setVolume(Number(event.currentTarget.value))}\n />\n </label>\n </div>\n </section>\n );\n}\n","\"use client\";\n\nimport { v4 as uuidv4 } from \"uuid\";\nimport { AiFillStar, AiOutlineStar } from \"react-icons/ai\";\n\nimport { FORM_RATING_NULL_VALUE } from \"@behindthemusictree/app-kit/genre-tree\";\n\nexport interface RatingProps {\n rating: number | null | undefined;\n handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\nexport default function Rating({ rating, handleChange }: RatingProps) {\n const instanceId = uuidv4();\n return (\n <div className=\"flex items-center\">\n {[...Array(6)].map((_, i) => (\n <div key={i} className={`relative ${i === 0 ? \"mr-4\" : \"mr-1\"}`}>\n <input\n id={`star-${instanceId}-${i}`}\n className=\"w-6 h-6 opacity-0\"\n type=\"radio\"\n name=\"rating\"\n value={i === 0 ? FORM_RATING_NULL_VALUE : i}\n checked={rating === (i === 0 ? null : i)}\n onChange={handleChange}\n />\n <label htmlFor={`star-${instanceId}-${i}`} className=\"cursor-pointer\">\n {i === 0 ? (\n <div className=\"flex\">\n <AiOutlineStar\n className={`w-7 h-7 absolute top-0 left-0 ${\n rating === FORM_RATING_NULL_VALUE ? \"text-[var(--color-accent-rating)]\" : \"text-[var(--color-text-muted)]\"\n }`}\n />\n <span className=\"flex-grow w-8\"></span>{\" \"}\n </div>\n ) : (\n <AiFillStar\n className={`w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? \"text-[var(--color-accent-rating)]\" : \"text-[var(--color-text-muted)]\"}`}\n />\n )}\n </label>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, type ComponentProps } from \"react\";\nimport { DetailPanel } from \"@behindthemusictree/ui\";\nimport type { RenderArtistLink, RenderPlaceLink, RenderSongLink } from \"@behindthemusictree/app-kit/genre-tree\";\nimport type { Scope } from \"@behindthemusictree/app-kit/transport\";\nimport { useEntityPanel } from \"./useEntityPanel\";\nimport type { SongGenreNavigation } from \"./song/useSongPanel\";\nimport type { GetGenreTreeShareUrl } from \"./share\";\n\nexport type EntityDetailPanelProps = {\n scope: Scope;\n getBackendBaseUrl: () => string;\n getArtistBackendBaseUrl?: () => string;\n getShareUrl?: GetGenreTreeShareUrl;\n songUuid: string | null;\n onSongUuidChange: (uuid: string | null) => void;\n artistUuid: string | null;\n onArtistUuidChange: (uuid: string | null) => void;\n /** Names render as buttons that open the artist by default. */\n renderArtistLink?: RenderArtistLink;\n /** Titles render as buttons that open the song by default. */\n renderSongLink?: RenderSongLink;\n renderPlaceLink?: RenderPlaceLink;\n collapsed?: boolean;\n edgeTab?: ComponentProps<typeof DetailPanel>[\"edgeTab\"];\n} & SongGenreNavigation;\n\n/** The song or artist detail in the shared left DetailPanel, for a host that has no genre tree. Renders nothing\n * while neither is set; a song takes precedence over an artist. */\nexport function EntityDetailPanel({\n scope,\n getBackendBaseUrl,\n getArtistBackendBaseUrl,\n getShareUrl,\n songUuid,\n onSongUuidChange,\n artistUuid,\n onArtistUuidChange,\n renderArtistLink,\n renderSongLink,\n renderPlaceLink,\n collapsed,\n edgeTab,\n ...navigation\n}: EntityDetailPanelProps) {\n // Keyed by uuid, so switching entities (including a host's back/forward) starts compact.\n const [expandedSongUuid, setExpandedSongUuid] = useState<string | null>(null);\n const [expandedArtistUuid, setExpandedArtistUuid] = useState<string | null>(null);\n\n const panel = useEntityPanel({\n scope,\n getBackendBaseUrl,\n getArtistBackendBaseUrl,\n getShareUrl,\n renderPlaceLink,\n renderArtistLink:\n renderArtistLink ??\n ((artist) =>\n artist.isSpecialPurpose ? (\n artist.name\n ) : (\n <button type=\"button\" onClick={() => onArtistUuidChange(artist.uuid)} className=\"hover:underline\">\n {artist.name}\n </button>\n )),\n renderSongLink:\n renderSongLink ??\n ((song) => (\n <button type=\"button\" onClick={() => onSongUuidChange(song.uuid)} className=\"hover:underline\">\n {song.title}\n </button>\n )),\n song: {\n uuid: songUuid,\n expanded: songUuid !== null && expandedSongUuid === songUuid,\n onExpandedChange: (on) => setExpandedSongUuid(on ? songUuid : null),\n onClose: () => onSongUuidChange(null),\n },\n artist: {\n uuid: artistUuid,\n expanded: artistUuid !== null && expandedArtistUuid === artistUuid,\n onExpandedChange: (on) => setExpandedArtistUuid(on ? artistUuid : null),\n onClose: () => onArtistUuidChange(null),\n },\n ...navigation,\n } as Parameters<typeof useEntityPanel>[0]);\n if (!panel) return null;\n\n return (\n <DetailPanel\n side=\"left\"\n title={panel.title}\n titleInSearch\n onClose={panel.onClose}\n collapsed={collapsed}\n expanded={panel.expanded}\n onExpandedChange={panel.onExpandedChange}\n aside={panel.extraContent}\n edgeTab={edgeTab}\n >\n {panel.extraContent && !panel.expanded ? (\n <>\n {panel.content}\n {panel.extraContent}\n </>\n ) : (\n panel.content\n )}\n </DetailPanel>\n );\n}\n"],"mappings":"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","names":["className","import_jsx_runtime","className","import_ui","import_jsx_runtime","className","import_react","import_react_dom","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_ui","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_lucide_react","import_ui","import_jsx_runtime","import_fa","import_ui","import_lucide_react","import_transport","import_jsx_runtime","import_jsx_runtime","import_react","import_react_query","import_lucide_react","import_ui","import_genre_tree_view","import_genre_tree","import_popup","import_genre_tree","import_react","import_react","import_genre_tree","import_popup","import_transport","import_jsx_runtime","import_jsx_runtime","className","import_genre_tree","import_react","import_genre_tree_view","import_player","import_jsx_runtime","className","import_genre_tree","import_react","import_genre_tree_view","import_player","import_jsx_runtime","className","import_react","import_jsx_runtime","import_react","import_lucide_react","import_ui","import_genre_tree","import_react","import_ui","import_jsx_runtime","className","import_genre_tree","import_jsx_runtime","import_genre_tree","import_jsx_runtime","import_genre_tree","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_genre_tree_view","import_ui","import_lucide_react","import_genre_tree","import_genre_tree","import_lucide_react","import_ui","import_lucide_react","import_ui","import_popup","import_react","import_lucide_react","import_fa","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_ui","import_genre_tree","import_player","import_react","import_jsx_runtime","className","import_jsx_runtime","className","import_jsx_runtime","import_ui","import_genre_tree","import_react","import_jsx_runtime","className","import_jsx_runtime","import_react","import_fa","import_ui","import_auth","import_transport","import_player","import_popup","import_transport","import_genre_tree","import_genre_tree","import_jsx_runtime","className","import_genre_tree","import_track_noun","import_jsx_runtime","artist","import_track_noun","import_si","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","ancestors","import_react","import_genre_tree","import_ui","import_jsx_runtime","import_ui","import_genre_tree","import_lucide_react","import_ui","import_genre_tree","import_player","import_jsx_runtime","import_ui","import_lucide_react","import_si","import_ui","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_ui","import_jsx_runtime","import_ui","import_jsx_runtime","import_react","import_react_query","import_ui","import_player","import_genre_tree","import_transport","import_player","import_genre_tree","import_fa","import_player","import_jsx_runtime","import_genre_tree","import_genre_tree","import_jsx_runtime","import_jsx_runtime","SongPageSchema","import_jsx_runtime","import_ui","import_genre_tree","import_react","import_lucide_react","import_ui","import_player","import_genre_tree","import_jsx_runtime","import_jsx_runtime","import_md","import_ui","import_jsx_runtime","import_jsx_runtime","className","genrePlaylist","import_genre_tree_view","import_react","import_lucide_react","import_genre_tree","import_track_noun","import_jsx_runtime","className","import_react","import_lucide_react","import_player","import_genre_tree","import_ui","import_lucide_react","import_genre_tree","import_player","import_jsx_runtime","import_jsx_runtime","className","import_genre_tree","import_jsx_runtime","uuidv4","import_react","import_ui","import_jsx_runtime"]}