@behindthemusictree/app-kit-ui 43.0.0 → 43.1.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.
@@ -48,14 +48,14 @@ __export(genre_tree_exports, {
48
48
  module.exports = __toCommonJS(genre_tree_exports);
49
49
 
50
50
  // src/genre-tree/GenreTreeView.tsx
51
- var import_react19 = require("react");
51
+ var import_react20 = require("react");
52
52
  var import_react_query3 = require("@tanstack/react-query");
53
53
  var import_lucide_react13 = require("lucide-react");
54
54
  var import_lucide_react14 = require("lucide-react");
55
- var import_ui22 = require("@behindthemusictree/ui");
55
+ var import_ui23 = require("@behindthemusictree/ui");
56
56
  var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
57
- var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
58
57
  var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
58
+ var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
59
59
  var import_popup4 = require("@behindthemusictree/app-kit/popup");
60
60
 
61
61
  // src/genre-tree/playlist-tree/size-metric.ts
@@ -724,6 +724,8 @@ function SearchBox({
724
724
  onClear,
725
725
  clearLabel,
726
726
  leading,
727
+ trailingAction,
728
+ trailingActionBreakpoint,
727
729
  className: className2,
728
730
  onFocus
729
731
  }) {
@@ -756,6 +758,8 @@ function SearchBox({
756
758
  onClear,
757
759
  clearLabel,
758
760
  leading,
761
+ trailingAction,
762
+ trailingActionBreakpoint,
759
763
  inputClassName: "focus-visible:ring-0"
760
764
  }
761
765
  ) });
@@ -856,7 +860,10 @@ function GenreSearch({
856
860
  placeholder,
857
861
  onQueryChange,
858
862
  extraGroups = [],
859
- onFocus
863
+ onFocus,
864
+ trailingAction,
865
+ trailingActionBreakpoint,
866
+ fullWidthBreakpoint = "md"
860
867
  }) {
861
868
  const { query, setQuery, results, canClear, clear, select } = (0, import_genre_tree9.useGenreSearch)({
862
869
  genrePlaylists,
@@ -884,7 +891,7 @@ function GenreSearch({
884
891
  (group) => active ? group : { ...group, items: [], status: "", loading: false }
885
892
  )
886
893
  ];
887
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("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", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
894
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: `genre-search w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 ${fullWidthBreakpoint === "sm" ? "max-sm:w-full sm:max-md:max-w-sm" : "max-md:w-full"}`, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
888
895
  SearchBox,
889
896
  {
890
897
  label,
@@ -905,7 +912,9 @@ function GenreSearch({
905
912
  onQueryChange?.("");
906
913
  } : void 0,
907
914
  leading: onPrevious && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", "aria-label": "Previous", title: "Previous", className: import_ui4.SEARCH_LEADING_BUTTON_CLASS, onClick: onPrevious, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }) }),
908
- onFocus
915
+ onFocus,
916
+ trailingAction,
917
+ trailingActionBreakpoint
909
918
  }
910
919
  ) });
911
920
  }
@@ -949,45 +958,93 @@ function GenreTreeSearch({
949
958
  return SearchGroups ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SearchGroups, { query: deferredQuery, focused, onSelectGenre, children: render }) : render([]);
950
959
  }
951
960
 
961
+ // src/genre-tree/GenreOverviewDetailPanel.tsx
962
+ var import_react9 = require("react");
963
+ var import_ui5 = require("@behindthemusictree/ui");
964
+ var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
965
+
966
+ // src/genre-tree/CommonsPhoto.tsx
967
+ var import_jsx_runtime16 = require("react/jsx-runtime");
968
+ function ExternalLink({ href, children }) {
969
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
970
+ }
971
+ function CommonsPhotoCredit({ image, creditLabel = "Photo" }) {
972
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("p", { className: "text-caption text-[var(--color-text-muted)]", children: [
973
+ creditLabel,
974
+ ": ",
975
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
976
+ ",",
977
+ " ",
978
+ image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
979
+ ] });
980
+ }
981
+ function CommonsCover({ image, alt }) {
982
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-cover bg-[var(--color-surface-muted)]" });
983
+ }
984
+ function CommonsPhoto({
985
+ image,
986
+ alt,
987
+ creditLabel = "Photo"
988
+ }) {
989
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
990
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
991
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
992
+ creditLabel,
993
+ ": ",
994
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
995
+ ",",
996
+ " ",
997
+ image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
998
+ ] })
999
+ ] });
1000
+ }
1001
+
1002
+ // src/genre-tree/GenreOverviewDetailPanel.tsx
1003
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1004
+ var GenreOverviewDetailPanel = (0, import_react9.forwardRef)(function GenreOverviewDetailPanel2({ genreUuid, scope, getBackendBaseUrl, criteriaOverviewSchema, cover, ...props }, ref) {
1005
+ const { data: overview } = (0, import_genre_tree10.useFetchGenreOverview)(genreUuid, scope, getBackendBaseUrl, criteriaOverviewSchema);
1006
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ui5.DetailPanel, { ...props, ref, cover: genreUuid && overview?.image ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CommonsCover, { image: overview.image, alt: overview.name }) : cover });
1007
+ });
1008
+
952
1009
  // src/genre-tree/GenreDetailPanel.tsx
953
- var import_react15 = require("react");
1010
+ var import_react16 = require("react");
954
1011
  var import_genre_tree_view4 = require("@behindthemusictree/genre-tree-view");
955
- var import_ui10 = require("@behindthemusictree/ui");
1012
+ var import_ui11 = require("@behindthemusictree/ui");
956
1013
  var import_lucide_react9 = require("lucide-react");
957
- var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
1014
+ var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
958
1015
 
959
1016
  // src/genre-tree/GenreInfoPanelBody.tsx
960
- var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
1017
+ var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
961
1018
 
962
1019
  // src/genre-tree/GenreActionBand.tsx
963
1020
  var import_lucide_react7 = require("lucide-react");
964
- var import_ui6 = require("@behindthemusictree/ui");
1021
+ var import_ui7 = require("@behindthemusictree/ui");
965
1022
 
966
1023
  // src/genre-tree/ShareActionButton.tsx
967
1024
  var import_lucide_react6 = require("lucide-react");
968
- var import_ui5 = require("@behindthemusictree/ui");
1025
+ var import_ui6 = require("@behindthemusictree/ui");
969
1026
  var import_popup2 = require("@behindthemusictree/app-kit/popup");
970
1027
 
971
1028
  // src/genre-tree/SharePopup.tsx
972
- var import_react10 = require("react");
1029
+ var import_react11 = require("react");
973
1030
  var import_lucide_react5 = require("lucide-react");
974
1031
  var import_fa = require("react-icons/fa");
975
1032
  var import_si = require("react-icons/si");
976
1033
 
977
1034
  // src/popup/Toast.tsx
978
- var import_react9 = require("react");
1035
+ var import_react10 = require("react");
979
1036
  var import_react_dom2 = require("react-dom");
980
- var import_jsx_runtime16 = require("react/jsx-runtime");
1037
+ var import_jsx_runtime18 = require("react/jsx-runtime");
981
1038
  function Toast({ message, onClose, durationMs = 2200 }) {
982
- const [mounted, setMounted] = (0, import_react9.useState)(false);
983
- (0, import_react9.useEffect)(() => {
1039
+ const [mounted, setMounted] = (0, import_react10.useState)(false);
1040
+ (0, import_react10.useEffect)(() => {
984
1041
  setMounted(true);
985
1042
  const timeout = window.setTimeout(onClose, durationMs);
986
1043
  return () => window.clearTimeout(timeout);
987
1044
  }, [durationMs, onClose]);
988
1045
  if (!mounted) return null;
989
1046
  return (0, import_react_dom2.createPortal)(
990
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1047
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
991
1048
  "div",
992
1049
  {
993
1050
  role: "status",
@@ -1002,12 +1059,12 @@ function Toast({ message, onClose, durationMs = 2200 }) {
1002
1059
  }
1003
1060
 
1004
1061
  // src/genre-tree/ShareDestinationButton.tsx
1005
- var import_jsx_runtime17 = require("react/jsx-runtime");
1062
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1006
1063
  var className = "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";
1007
1064
  function Contents({ icon, label }) {
1008
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1009
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("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)]", children: icon }),
1010
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "max-w-full truncate", children: label })
1065
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1066
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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)]", children: icon }),
1067
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "max-w-full truncate", children: label })
1011
1068
  ] });
1012
1069
  }
1013
1070
  function ShareDestinationButton({
@@ -1019,29 +1076,29 @@ function ShareDestinationButton({
1019
1076
  ariaLabel
1020
1077
  }) {
1021
1078
  if (href) {
1022
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Contents, { icon, label }) });
1079
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Contents, { icon, label }) });
1023
1080
  }
1024
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Contents, { icon, label }) });
1081
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Contents, { icon, label }) });
1025
1082
  }
1026
1083
 
1027
1084
  // src/genre-tree/SharePreviewCard.tsx
1028
1085
  var import_lucide_react4 = require("lucide-react");
1029
- var import_jsx_runtime18 = require("react/jsx-runtime");
1086
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1030
1087
  function SharePreviewCard({ target, url }) {
1031
1088
  const Icon = { genre: import_lucide_react4.Music2, artist: import_lucide_react4.UserRound, song: import_lucide_react4.Music }[target.kind];
1032
1089
  const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
1033
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
1034
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
1035
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
1036
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
1037
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
1038
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
1090
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
1091
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
1092
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
1093
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
1094
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
1095
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
1039
1096
  ] })
1040
1097
  ] }) });
1041
1098
  }
1042
1099
 
1043
1100
  // src/genre-tree/SharePopup.tsx
1044
- var import_jsx_runtime19 = require("react/jsx-runtime");
1101
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1045
1102
  function resolveAbsoluteUrl(url) {
1046
1103
  try {
1047
1104
  const parsed = new URL(url, window.location.href);
@@ -1074,20 +1131,20 @@ async function copyText(text) {
1074
1131
  }
1075
1132
  }
1076
1133
  function SharePopup({ target, url, onClose }) {
1077
- const [absoluteUrl, setAbsoluteUrl] = (0, import_react10.useState)(url);
1078
- const [copyStatus, setCopyStatus] = (0, import_react10.useState)("idle");
1079
- const [canUseNativeShare, setCanUseNativeShare] = (0, import_react10.useState)(false);
1080
- const [shareError, setShareError] = (0, import_react10.useState)(null);
1081
- const [toastId, setToastId] = (0, import_react10.useState)(0);
1082
- (0, import_react10.useEffect)(() => {
1134
+ const [absoluteUrl, setAbsoluteUrl] = (0, import_react11.useState)(url);
1135
+ const [copyStatus, setCopyStatus] = (0, import_react11.useState)("idle");
1136
+ const [canUseNativeShare, setCanUseNativeShare] = (0, import_react11.useState)(false);
1137
+ const [shareError, setShareError] = (0, import_react11.useState)(null);
1138
+ const [toastId, setToastId] = (0, import_react11.useState)(0);
1139
+ (0, import_react11.useEffect)(() => {
1083
1140
  setAbsoluteUrl(resolveAbsoluteUrl(url) ?? "");
1084
1141
  setCopyStatus("idle");
1085
1142
  setShareError(null);
1086
1143
  }, [url]);
1087
- (0, import_react10.useEffect)(() => {
1144
+ (0, import_react11.useEffect)(() => {
1088
1145
  setCanUseNativeShare(typeof navigator !== "undefined" && typeof navigator.share === "function");
1089
1146
  }, []);
1090
- const destinationUrls = (0, import_react10.useMemo)(() => {
1147
+ const destinationUrls = (0, import_react11.useMemo)(() => {
1091
1148
  if (!absoluteUrl) return null;
1092
1149
  const message = `${target.name} \u2014 ${absoluteUrl}`;
1093
1150
  return {
@@ -1105,7 +1162,7 @@ function SharePopup({ target, url, onClose }) {
1105
1162
  setCopyStatus(copied ? "idle" : "failed");
1106
1163
  if (copied) setToastId((id) => id + 1);
1107
1164
  };
1108
- const dismissToast = (0, import_react10.useCallback)(() => setToastId(0), []);
1165
+ const dismissToast = (0, import_react11.useCallback)(() => setToastId(0), []);
1109
1166
  const handleNativeShare = async () => {
1110
1167
  if (!absoluteUrl || !navigator.share) return;
1111
1168
  setShareError(null);
@@ -1116,8 +1173,8 @@ function SharePopup({ target, url, onClose }) {
1116
1173
  setShareError("Could not open the share options.");
1117
1174
  }
1118
1175
  };
1119
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1120
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1176
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1177
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1121
1178
  BasePopup_default,
1122
1179
  {
1123
1180
  title: "Share",
@@ -1132,70 +1189,70 @@ function SharePopup({ target, url, onClose }) {
1132
1189
  titleTextClassName: "!text-xl !font-semibold !text-[var(--color-text)]",
1133
1190
  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)]",
1134
1191
  contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
1135
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col gap-4", children: [
1136
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SharePreviewCard, { target, url: absoluteUrl || url }),
1137
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
1138
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1192
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-4", children: [
1193
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SharePreviewCard, { target, url: absoluteUrl || url }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
1195
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1139
1196
  ShareDestinationButton,
1140
1197
  {
1141
1198
  label: "Copy Link",
1142
- icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
1199
+ icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
1143
1200
  onClick: () => void handleCopy(),
1144
1201
  ariaLabel: "Copy link",
1145
1202
  disabled: !absoluteUrl
1146
1203
  }
1147
1204
  ),
1148
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1205
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1149
1206
  ShareDestinationButton,
1150
1207
  {
1151
1208
  label: "WhatsApp",
1152
- icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fa.FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
1209
+ icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa.FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
1153
1210
  href: destinationUrls?.whatsapp,
1154
1211
  ariaLabel: `Share ${target.name} via WhatsApp`,
1155
1212
  disabled: !absoluteUrl
1156
1213
  }
1157
1214
  ),
1158
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1215
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1159
1216
  ShareDestinationButton,
1160
1217
  {
1161
1218
  label: "Gmail",
1162
- icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_si.SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
1219
+ icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_si.SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
1163
1220
  href: destinationUrls?.gmail,
1164
1221
  ariaLabel: `Email ${target.name} with Gmail`,
1165
1222
  disabled: !absoluteUrl
1166
1223
  }
1167
1224
  ),
1168
- canUseNativeShare && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1225
+ canUseNativeShare && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1169
1226
  ShareDestinationButton,
1170
1227
  {
1171
1228
  label: "More",
1172
- icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
1229
+ icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
1173
1230
  onClick: () => void handleNativeShare(),
1174
1231
  ariaLabel: "More sharing options",
1175
1232
  disabled: !absoluteUrl
1176
1233
  }
1177
1234
  )
1178
1235
  ] }),
1179
- copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
1180
- shareError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
1236
+ copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
1237
+ shareError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
1181
1238
  ] })
1182
1239
  }
1183
1240
  ),
1184
- toastId > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
1241
+ toastId > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
1185
1242
  ] });
1186
1243
  }
1187
1244
 
1188
1245
  // src/genre-tree/ShareActionButton.tsx
1189
- var import_jsx_runtime20 = require("react/jsx-runtime");
1246
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1190
1247
  function ShareActionButton({ target, url }) {
1191
1248
  const { showPopup, hidePopup } = (0, import_popup2.usePopup)();
1192
1249
  const openSharePopup = () => {
1193
- showPopup(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SharePopup, { target, url, onClose: hidePopup }));
1250
+ showPopup(/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SharePopup, { target, url, onClose: hidePopup }));
1194
1251
  };
1195
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1196
- import_ui5.ActionButton,
1252
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1253
+ import_ui6.ActionButton,
1197
1254
  {
1198
- icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Share2, { "aria-hidden": "true", className: "w-5 h-5" }),
1255
+ icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react6.Share2, { "aria-hidden": "true", className: "w-5 h-5" }),
1199
1256
  label: "Share",
1200
1257
  "aria-label": `Share ${target.name}`,
1201
1258
  title: `Share ${target.name}`,
@@ -1205,7 +1262,7 @@ function ShareActionButton({ target, url }) {
1205
1262
  }
1206
1263
 
1207
1264
  // src/genre-tree/GenreActionBand.tsx
1208
- var import_jsx_runtime21 = require("react/jsx-runtime");
1265
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1209
1266
  function GenreActionBand({
1210
1267
  node,
1211
1268
  playActions,
@@ -1226,24 +1283,24 @@ function GenreActionBand({
1226
1283
  items.push({
1227
1284
  key: "zoom-in",
1228
1285
  label: "Focus",
1229
- icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
1286
+ icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react7.ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
1230
1287
  onClick: onZoomIn
1231
1288
  });
1232
1289
  }
1233
1290
  if (onAddChild) {
1234
- adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
1291
+ adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react7.Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
1235
1292
  }
1236
1293
  if (onRename) {
1237
- adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
1294
+ adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react7.Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
1238
1295
  }
1239
1296
  if (onChangeParent) {
1240
- adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
1297
+ adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react7.MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
1241
1298
  }
1242
1299
  if (onToggleSide) {
1243
1300
  adminItems.push({
1244
1301
  key: "toggle-side",
1245
1302
  label: side === "pop" ? "Make core" : "Make pop",
1246
- icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
1303
+ icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react7.ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
1247
1304
  onClick: onToggleSide,
1248
1305
  disabled: !!toggleSideDisabledReason,
1249
1306
  title: toggleSideDisabledReason
@@ -1258,17 +1315,17 @@ function GenreActionBand({
1258
1315
  disabled: action.enabled ? !action.enabled(node) : false
1259
1316
  });
1260
1317
  }
1261
- const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui6.ActionButton, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
1318
+ const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ui7.ActionButton, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
1262
1319
  if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;
1263
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui6.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1264
- import_ui6.ActionBand,
1320
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ui7.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1321
+ import_ui7.ActionBand,
1265
1322
  {
1266
1323
  className: "genre-action-band",
1267
1324
  section: { title: "Admin", label: "Admin actions", children: renderItems(adminItems) },
1268
1325
  children: [
1269
1326
  playActions,
1270
1327
  renderItems(items),
1271
- shareTarget && shareUrl && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
1328
+ shareTarget && shareUrl && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
1272
1329
  ]
1273
1330
  }
1274
1331
  ) });
@@ -1276,12 +1333,12 @@ function GenreActionBand({
1276
1333
 
1277
1334
  // src/genre-tree/GenrePlayActions.tsx
1278
1335
  var import_lucide_react8 = require("lucide-react");
1279
- var import_ui7 = require("@behindthemusictree/ui");
1280
- var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
1336
+ var import_ui8 = require("@behindthemusictree/ui");
1337
+ var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
1281
1338
  var import_player4 = require("@behindthemusictree/app-kit/player");
1282
1339
 
1283
1340
  // src/genre-tree/RegionGlobeIcon.tsx
1284
- var import_react11 = require("react");
1341
+ var import_react12 = require("react");
1285
1342
 
1286
1343
  // src/genre-tree/regionGlobePaths.ts
1287
1344
  var REGION_GLOBE_PATHS = {
@@ -1292,11 +1349,11 @@ var REGION_GLOBE_PATHS = {
1292
1349
  var REGION_GLOBES = ["africa", "americas", "asia"];
1293
1350
 
1294
1351
  // src/genre-tree/RegionGlobeIcon.tsx
1295
- var import_jsx_runtime22 = require("react/jsx-runtime");
1352
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1296
1353
  var ROTATION_INTERVAL_MS = 3e3;
1297
1354
  function RegionGlobeIcon({ className: className2 }) {
1298
- const [index, setIndex] = (0, import_react11.useState)(0);
1299
- (0, import_react11.useEffect)(() => {
1355
+ const [index, setIndex] = (0, import_react12.useState)(0);
1356
+ (0, import_react12.useEffect)(() => {
1300
1357
  const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
1301
1358
  let timer;
1302
1359
  const sync = () => {
@@ -1310,51 +1367,51 @@ function RegionGlobeIcon({ className: className2 }) {
1310
1367
  clearInterval(timer);
1311
1368
  };
1312
1369
  }, []);
1313
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
1370
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
1314
1371
  }
1315
1372
 
1316
1373
  // src/genre-tree/treeMarkPath.ts
1317
1374
  var TREE_MARK_PATH = "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";
1318
1375
 
1319
1376
  // src/genre-tree/TreeMarkIcon.tsx
1320
- var import_jsx_runtime23 = require("react/jsx-runtime");
1377
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1321
1378
  function TreeMarkIcon({ className: className2 }) {
1322
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
1379
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
1323
1380
  }
1324
1381
 
1325
1382
  // src/genre-tree/GenrePlayActions.tsx
1326
- var import_jsx_runtime24 = require("react/jsx-runtime");
1383
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1327
1384
  function PlayIcon({ kind }) {
1328
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
1329
- kind === "tree" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1330
- kind === "map" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1331
- kind === "tree-map" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
1332
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
1333
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
1385
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
1386
+ kind === "tree" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1387
+ kind === "map" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1388
+ kind === "tree-map" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
1389
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
1390
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
1334
1391
  ] }),
1335
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react8.Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
1392
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react8.Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
1336
1393
  ] });
1337
1394
  }
1338
1395
  function playOptions(playlist) {
1339
1396
  if (!("genreOnlyTracksCount" in playlist)) return [{ key: "all", label: "Play", icon: "play", count: playlist.tracksCount }];
1340
- const direct = { key: "direct", label: "Genre", icon: "play", selection: { coverage: "genreOnly" }, count: (0, import_genre_tree10.genreMusicCount)(playlist, { coverage: "genreOnly" }) };
1397
+ const direct = { key: "direct", label: "Genre", icon: "play", selection: { coverage: "genreOnly" }, count: (0, import_genre_tree11.genreMusicCount)(playlist, { coverage: "genreOnly" }) };
1341
1398
  const scopes = playlist.genreAndSubgenresTracksCount;
1342
1399
  const inclusive = (label, icon, subgenres) => {
1343
1400
  const selection = { coverage: "genreAndSubgenres", subgenres };
1344
- return { key: subgenres, label, icon, selection, count: (0, import_genre_tree10.genreMusicCount)(playlist, selection) };
1401
+ return { key: subgenres, label, icon, selection, count: (0, import_genre_tree11.genreMusicCount)(playlist, selection) };
1345
1402
  };
1346
1403
  return "canonical" in scopes ? [direct, inclusive("Canonical", "tree", "canonical"), inclusive("Regional", "map", "regional"), inclusive("All", "tree-map", "all")] : [direct, inclusive("All", "map", "all")];
1347
1404
  }
1348
1405
  function GenrePlayActions({ genrePlaylist, playback }) {
1349
1406
  const { isPlaying, setIsPlaying } = (0, import_player4.usePlayer)();
1350
1407
  const options = playOptions(genrePlaylist);
1351
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: options.map((option) => {
1352
- const isCurrent = playback.playing?.uuid === genrePlaylist.uuid && (option.selection === void 0 || playback.playing.selectionKey === "" || playback.playing.selectionKey === (0, import_genre_tree10.genreMusicSelectionKey)(option.selection).join());
1408
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: options.map((option) => {
1409
+ const isCurrent = playback.playing?.uuid === genrePlaylist.uuid && (option.selection === void 0 || playback.playing.selectionKey === "" || playback.playing.selectionKey === (0, import_genre_tree11.genreMusicSelectionKey)(option.selection).join());
1353
1410
  const playing = isCurrent && isPlaying;
1354
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1355
- import_ui7.ActionButton,
1411
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1412
+ import_ui8.ActionButton,
1356
1413
  {
1357
- icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react8.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PlayIcon, { kind: option.icon }),
1414
+ icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react8.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PlayIcon, { kind: option.icon }),
1358
1415
  label: playing ? "Pause" : option.label,
1359
1416
  caption: String(option.count),
1360
1417
  disabled: option.count === 0,
@@ -1373,24 +1430,24 @@ function GenrePlayActions({ genrePlaylist, playback }) {
1373
1430
  }
1374
1431
 
1375
1432
  // src/genre-tree/GenreDetailExtras.tsx
1376
- var import_ui9 = require("@behindthemusictree/ui");
1377
- var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
1433
+ var import_ui10 = require("@behindthemusictree/ui");
1434
+ var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
1378
1435
 
1379
1436
  // src/genre-tree/ClampedText.tsx
1380
- var import_react12 = require("react");
1381
- var import_jsx_runtime25 = require("react/jsx-runtime");
1437
+ var import_react13 = require("react");
1438
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1382
1439
  function ClampedText({ children, className: className2 = "" }) {
1383
- const ref = (0, import_react12.useRef)(null);
1384
- const [expanded, setExpanded] = (0, import_react12.useState)(false);
1385
- const [overflows, setOverflows] = (0, import_react12.useState)(false);
1386
- (0, import_react12.useLayoutEffect)(() => {
1440
+ const ref = (0, import_react13.useRef)(null);
1441
+ const [expanded, setExpanded] = (0, import_react13.useState)(false);
1442
+ const [overflows, setOverflows] = (0, import_react13.useState)(false);
1443
+ (0, import_react13.useLayoutEffect)(() => {
1387
1444
  const element = ref.current;
1388
1445
  if (!element || expanded) return;
1389
1446
  setOverflows(element.scrollHeight > element.clientHeight);
1390
1447
  }, [children, expanded]);
1391
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
1392
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
1393
- (overflows || expanded) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1448
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
1449
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
1450
+ (overflows || expanded) && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1394
1451
  "button",
1395
1452
  {
1396
1453
  type: "button",
@@ -1403,35 +1460,12 @@ function ClampedText({ children, className: className2 = "" }) {
1403
1460
  ] });
1404
1461
  }
1405
1462
 
1406
- // src/genre-tree/CommonsPhoto.tsx
1407
- var import_jsx_runtime26 = require("react/jsx-runtime");
1408
- function ExternalLink({ href, children }) {
1409
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
1410
- }
1411
- function CommonsPhoto({
1412
- image,
1413
- alt,
1414
- creditLabel = "Photo"
1415
- }) {
1416
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
1417
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
1418
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
1419
- creditLabel,
1420
- ": ",
1421
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
1422
- ",",
1423
- " ",
1424
- image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
1425
- ] })
1426
- ] });
1427
- }
1428
-
1429
1463
  // src/genre-tree/GenrePlaylistTracks.tsx
1430
- var import_react13 = require("react");
1464
+ var import_react14 = require("react");
1431
1465
  var import_react_query = require("@tanstack/react-query");
1432
1466
  var import_zod = require("zod");
1433
1467
  var import_fa2 = require("react-icons/fa");
1434
- var import_ui8 = require("@behindthemusictree/ui");
1468
+ var import_ui9 = require("@behindthemusictree/ui");
1435
1469
  var import_auth = require("@behindthemusictree/app-kit/auth");
1436
1470
  var import_transport2 = require("@behindthemusictree/app-kit/transport");
1437
1471
  var import_transport3 = require("@behindthemusictree/app-kit/transport");
@@ -1440,23 +1474,23 @@ var import_player5 = require("@behindthemusictree/app-kit/player");
1440
1474
  var import_player6 = require("@behindthemusictree/app-kit/player");
1441
1475
  var import_popup3 = require("@behindthemusictree/app-kit/popup");
1442
1476
  var import_transport5 = require("@behindthemusictree/app-kit/transport");
1443
- var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
1444
1477
  var import_genre_tree13 = require("@behindthemusictree/app-kit/genre-tree");
1445
1478
  var import_genre_tree14 = require("@behindthemusictree/app-kit/genre-tree");
1446
1479
  var import_genre_tree15 = require("@behindthemusictree/app-kit/genre-tree");
1447
1480
  var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
1481
+ var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
1448
1482
 
1449
1483
  // src/genre-tree/MusicBrainzRecordingLink.tsx
1450
- var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
1451
- var import_jsx_runtime27 = require("react/jsx-runtime");
1484
+ var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
1485
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1452
1486
  function MusicBrainzRecordingLink({
1453
1487
  song,
1454
1488
  children,
1455
1489
  className: className2 = ""
1456
1490
  }) {
1457
- const url = (0, import_genre_tree11.musicBrainzRecordingUrl)(song);
1458
- if (!url) return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_jsx_runtime27.Fragment, { children });
1459
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1491
+ const url = (0, import_genre_tree12.musicBrainzRecordingUrl)(song);
1492
+ if (!url) return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children });
1493
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1460
1494
  "a",
1461
1495
  {
1462
1496
  href: url,
@@ -1471,11 +1505,11 @@ function MusicBrainzRecordingLink({
1471
1505
  }
1472
1506
 
1473
1507
  // src/genre-tree/GenrePlaylistTracks.tsx
1474
- var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
1508
+ var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
1475
1509
  var import_track_noun = require("@behindthemusictree/app-kit/track-noun");
1476
- var import_jsx_runtime28 = require("react/jsx-runtime");
1510
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1477
1511
  var CATALOGUE_PAGE_SIZE = 100;
1478
- var SongPageSchema = (0, import_transport3.PaginatedResponseSchema)(import_genre_tree15.SongDetailedSchema).extend({
1512
+ var SongPageSchema = (0, import_transport3.PaginatedResponseSchema)(import_genre_tree16.SongDetailedSchema).extend({
1479
1513
  overallTotal: import_zod.z.number().nullable(),
1480
1514
  page: import_zod.z.number().nullable(),
1481
1515
  totalPages: import_zod.z.number().nullable()
@@ -1504,7 +1538,7 @@ function GenrePlaylistTracks({
1504
1538
  renderTracksToolbar,
1505
1539
  artist = null
1506
1540
  }) {
1507
- const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0, import_genre_tree16.useTrackList)();
1541
+ const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0, import_genre_tree17.useTrackList)();
1508
1542
  const { session, sessionRestored } = (0, import_auth.useSession)();
1509
1543
  const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player5.usePlayer)();
1510
1544
  const { showPopup } = (0, import_popup3.usePopup)();
@@ -1514,18 +1548,18 @@ function GenrePlaylistTracks({
1514
1548
  const { fetchBound } = (0, import_transport2.usePlaybackFetch)(getBackendBaseUrl);
1515
1549
  const playback = (0, import_transport2.usePlaybackContext)();
1516
1550
  const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
1517
- queryKey: [...scope === "me" ? uuid ? import_genre_tree13.genrePlaylistQueryKeys.me.tracks(uuid) : ["missing-personal-genre-playlist", genreUuid] : artist ? [...import_genre_tree14.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), "artist", artist.uuid] : import_genre_tree14.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), ...playback.key ? [playback.key] : []],
1551
+ queryKey: [...scope === "me" ? uuid ? import_genre_tree14.genrePlaylistQueryKeys.me.tracks(uuid) : ["missing-personal-genre-playlist", genreUuid] : artist ? [...import_genre_tree15.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), "artist", artist.uuid] : import_genre_tree15.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), ...playback.key ? [playback.key] : []],
1518
1552
  queryFn: async ({ pageParam }) => {
1519
1553
  if (scope === "me") {
1520
1554
  if (!uuid) throw new Error("Personal genre has no playlist");
1521
1555
  return fetchGenrePlaylistTracksPage(uuid, scope, Number(pageParam));
1522
1556
  }
1523
1557
  const response = await fetchBound(
1524
- import_genre_tree14.libraryEndpoints.reference.songs.list(),
1558
+ import_genre_tree15.libraryEndpoints.reference.songs.list(),
1525
1559
  true,
1526
1560
  false,
1527
1561
  {},
1528
- { genre: genreUuid, ...(0, import_genre_tree12.genreMusicQueryParams)(selection), ...artist && { artist: artist.uuid }, pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...pageParam && { cursor: pageParam } }
1562
+ { genre: genreUuid, ...(0, import_genre_tree13.genreMusicQueryParams)(selection), ...artist && { artist: artist.uuid }, pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...pageParam && { cursor: pageParam } }
1529
1563
  );
1530
1564
  const parsed = (0, import_transport4.parseWithLog)(SongPageSchema, response, "GenrePlaylistTracks");
1531
1565
  return { tracks: parsed.results, total: parsed.overallTotal, nextPage: parsed.next ? nextCursor(parsed.next) : null };
@@ -1536,8 +1570,8 @@ function GenrePlaylistTracks({
1536
1570
  retry: (failureCount, error) => failureCount < 1 && error instanceof DOMException && error.name === "AbortError",
1537
1571
  retryDelay: 0
1538
1572
  });
1539
- const [sentinel, setSentinel] = (0, import_react13.useState)(null);
1540
- (0, import_react13.useEffect)(() => {
1573
+ const [sentinel, setSentinel] = (0, import_react14.useState)(null);
1574
+ (0, import_react14.useEffect)(() => {
1541
1575
  if (!hasNextPage || isFetchingNextPage || !sentinel) return;
1542
1576
  const observer = new IntersectionObserver((entries) => {
1543
1577
  if (entries.some((entry) => entry.isIntersecting)) {
@@ -1559,36 +1593,36 @@ function GenrePlaylistTracks({
1559
1593
  }) : scope === "reference" ? playNewTrackListFromGenreCatalogue({ uuid: genreUuid, name: genreName }, scope, { startSongUuid, ...selection && { selection } }) : genrePlaylist ? playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid }) : Promise.reject(new Error("Personal genre has no playlist"));
1560
1594
  started.catch((error) => {
1561
1595
  console.error("Failed to play genre playlist:", error);
1562
- if (error instanceof import_genre_tree16.TracksFailureAlreadyReportedError) return;
1563
- showPopup(/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport5.AppError ? error.code : import_transport5.ErrorCode.CLIENT_UNKNOWN }));
1596
+ if (error instanceof import_genre_tree17.TracksFailureAlreadyReportedError) return;
1597
+ showPopup(/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport5.AppError ? error.code : import_transport5.ErrorCode.CLIENT_UNKNOWN }));
1564
1598
  });
1565
1599
  };
1566
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui8.PanelSection, { title: `${(0, import_track_noun.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { children: [
1600
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: `${(0, import_track_noun.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
1567
1601
  renderTracksToolbar?.(),
1568
- scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui8.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { role: "alert", children: [
1602
+ scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("p", { role: "alert", children: [
1569
1603
  "Couldn't load ",
1570
1604
  trackNoun.plural,
1571
1605
  ".",
1572
1606
  " ",
1573
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
1574
- ] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
1607
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
1608
+ ] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
1575
1609
  tracks.map((track, index) => {
1576
1610
  const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
1577
1611
  const isCurrent = playerTrackObject?.track.id === track.uuid;
1578
1612
  const isPlaying = isCurrent && playState === import_player6.PlayStates.PLAYING;
1579
- const text = /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: TEXT_CELL, children: [
1580
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree15.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
1581
- track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
1582
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_genre_tree17.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
1583
- track.album && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
1613
+ const text = /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: TEXT_CELL, children: [
1614
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree16.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
1615
+ track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
1616
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_genre_tree18.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
1617
+ track.album && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
1584
1618
  ] });
1585
1619
  const leading = renderSongLeading?.(track, index);
1586
1620
  const actions = renderSongActions?.(track);
1587
- const isUnplayable = (0, import_genre_tree15.isSong)(track) && (0, import_genre_tree15.songUnplayableReason)(track) !== null;
1621
+ const isUnplayable = (0, import_genre_tree16.isSong)(track) && (0, import_genre_tree16.songUnplayableReason)(track) !== null;
1588
1622
  if (isUnplayable) {
1589
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
1623
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
1590
1624
  leading,
1591
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1625
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1592
1626
  "button",
1593
1627
  {
1594
1628
  type: "button",
@@ -1596,27 +1630,27 @@ function GenrePlaylistTracks({
1596
1630
  "aria-disabled": "true",
1597
1631
  "aria-label": label,
1598
1632
  className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
1599
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa2.FaPlay, { size: 10 })
1633
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_fa2.FaPlay, { size: 10 })
1600
1634
  }
1601
1635
  ),
1602
1636
  text,
1603
1637
  actions
1604
1638
  ] }, track.uuid);
1605
1639
  }
1606
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1640
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1607
1641
  "li",
1608
1642
  {
1609
1643
  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)]" : ""}`,
1610
1644
  children: [
1611
1645
  leading,
1612
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1646
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1613
1647
  "button",
1614
1648
  {
1615
1649
  type: "button",
1616
1650
  "aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
1617
1651
  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 !== import_player6.PlayStates.STOPPED ? "opacity-100" : "opacity-0 [@media(pointer:coarse)]:opacity-100"}`,
1618
1652
  onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
1619
- children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui8.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa2.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa2.FaPlay, { size: 10 })
1653
+ children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_fa2.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_fa2.FaPlay, { size: 10 })
1620
1654
  }
1621
1655
  ),
1622
1656
  text,
@@ -1626,7 +1660,7 @@ function GenrePlaylistTracks({
1626
1660
  track.uuid
1627
1661
  );
1628
1662
  }),
1629
- hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
1663
+ hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
1630
1664
  ] })
1631
1665
  ] }) });
1632
1666
  }
@@ -1634,8 +1668,9 @@ function GenrePlaylistTracks({
1634
1668
  // src/genre-tree/GenreDetailExtras.tsx
1635
1669
  var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
1636
1670
  var import_si2 = require("react-icons/si");
1637
- var import_jsx_runtime29 = require("react/jsx-runtime");
1671
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1638
1672
  function GenreDetailExtras({
1673
+ imageInCover = false,
1639
1674
  genreUuid,
1640
1675
  genrePlaylist,
1641
1676
  genreName,
@@ -1653,25 +1688,25 @@ function GenreDetailExtras({
1653
1688
  ...trackSlots
1654
1689
  }) {
1655
1690
  const trackNoun = (0, import_track_noun2.useTrackNoun)();
1656
- const { data: overview, isPending } = (0, import_genre_tree18.useFetchGenreOverview)(
1691
+ const { data: overview, isPending } = (0, import_genre_tree19.useFetchGenreOverview)(
1657
1692
  genreUuid,
1658
1693
  scope,
1659
1694
  getBackendBaseUrl,
1660
1695
  criteriaOverviewSchema
1661
1696
  );
1662
1697
  if (isPending) {
1663
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
1664
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.Skeleton, { className: "h-4 w-3/4" }) }) }),
1698
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
1699
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.Skeleton, { className: "h-4 w-3/4" }) }) }),
1665
1700
  family
1666
1701
  ] });
1667
1702
  }
1668
- if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_jsx_runtime29.Fragment, { children: family });
1703
+ if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: family });
1669
1704
  const { summary, summarySourceUrl, essentialSongs, image } = overview;
1670
1705
  const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
1671
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
1672
- image && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CommonsPhoto, { image, alt: overview.name, creditLabel: "Image" }),
1673
- (summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
1674
- summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1706
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
1707
+ image && (imageInCover ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CommonsPhotoCredit, { image, creditLabel: "Image" }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CommonsPhoto, { image, alt: overview.name, creditLabel: "Image" })),
1708
+ (summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
1709
+ summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1675
1710
  "a",
1676
1711
  {
1677
1712
  href: summarySourceUrl,
@@ -1679,12 +1714,12 @@ function GenreDetailExtras({
1679
1714
  rel: "noopener noreferrer",
1680
1715
  className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
1681
1716
  children: [
1682
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1717
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1683
1718
  "Wikipedia"
1684
1719
  ]
1685
1720
  }
1686
1721
  ),
1687
- wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1722
+ wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1688
1723
  "a",
1689
1724
  {
1690
1725
  href: wikidataUrl,
@@ -1692,17 +1727,17 @@ function GenreDetailExtras({
1692
1727
  rel: "noopener noreferrer",
1693
1728
  className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
1694
1729
  children: [
1695
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1730
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1696
1731
  "Wikidata"
1697
1732
  ]
1698
1733
  }
1699
1734
  )
1700
1735
  ] }) }),
1701
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
1736
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
1702
1737
  family,
1703
1738
  renderGenreDetailExtras?.(overview),
1704
- (renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
1705
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1739
+ (renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
1740
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1706
1741
  GenrePlaylistTracks,
1707
1742
  {
1708
1743
  genreUuid,
@@ -1720,10 +1755,10 @@ function GenreDetailExtras({
1720
1755
  }
1721
1756
 
1722
1757
  // src/genre-tree/GenreInfoPanelBody.tsx
1723
- var import_jsx_runtime30 = require("react/jsx-runtime");
1724
- var import_react14 = require("react");
1758
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1759
+ var import_react15 = require("react");
1725
1760
  function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
1726
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
1761
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
1727
1762
  }
1728
1763
  function GenreInfoPanelBody({
1729
1764
  toolbar,
@@ -1738,12 +1773,12 @@ function GenreInfoPanelBody({
1738
1773
  band,
1739
1774
  extras
1740
1775
  }) {
1741
- const summary = scope === "reference" ? import_genre_tree19.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
1742
- const selection = summary ? (0, import_genre_tree19.defaultGenreMusicSelection)(summary) : void 0;
1743
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
1776
+ const summary = scope === "reference" ? import_genre_tree20.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
1777
+ const selection = summary ? (0, import_genre_tree20.defaultGenreMusicSelection)(summary) : void 0;
1778
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
1744
1779
  toolbar,
1745
- genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenreActionBand, { ...band }),
1746
- /* @__PURE__ */ (0, import_react14.createElement)(
1780
+ genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(GenreActionBand, { ...band }),
1781
+ /* @__PURE__ */ (0, import_react15.createElement)(
1747
1782
  GenreDetailExtras,
1748
1783
  {
1749
1784
  ...extras,
@@ -1762,7 +1797,7 @@ function GenreInfoPanelBody({
1762
1797
  }
1763
1798
 
1764
1799
  // src/genre-tree/GenreDetailPanel.tsx
1765
- var import_jsx_runtime31 = require("react/jsx-runtime");
1800
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1766
1801
  var RELATIVE_ITEM_COUNT = 1;
1767
1802
  function toNode(genre, parentId) {
1768
1803
  return {
@@ -1787,11 +1822,11 @@ function useGenreDetailContent({
1787
1822
  expanded,
1788
1823
  treeStyles
1789
1824
  }) {
1790
- const result = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
1825
+ const result = (0, import_genre_tree21.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
1791
1826
  const detail = result.status === "success" ? result.genre : void 0;
1792
1827
  const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
1793
1828
  const playback = hostPlayback ?? defaultPlayback;
1794
- const view = (0, import_react15.useMemo)(() => {
1829
+ const view = (0, import_react16.useMemo)(() => {
1795
1830
  if (!detail) return null;
1796
1831
  const rootColor = (0, import_genre_tree_view4.getGenreTreeColor)(detail.root.wikidataId);
1797
1832
  const relative = (genre, parentId) => ({
@@ -1805,7 +1840,7 @@ function useGenreDetailContent({
1805
1840
  id: detail.uuid,
1806
1841
  parentId: detail.parent?.uuid ?? null,
1807
1842
  name: detail.name,
1808
- itemCount: scope === "reference" ? (0, import_genre_tree20.genreMusicCount)(detail.criteriaPlaylist ? import_genre_tree20.GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist) : import_genre_tree20.GenreCatalogueCountsSchema.parse(detail.catalogue)) : detail.tracksCount,
1843
+ itemCount: scope === "reference" ? (0, import_genre_tree21.genreMusicCount)(detail.criteriaPlaylist ? import_genre_tree21.GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist) : import_genre_tree21.GenreCatalogueCountsSchema.parse(detail.catalogue)) : detail.tracksCount,
1809
1844
  wikidataId: detail.wikidataId
1810
1845
  },
1811
1846
  fill: own.fill,
@@ -1820,24 +1855,24 @@ function useGenreDetailContent({
1820
1855
  if (result.status === "not-found") return {
1821
1856
  name: null,
1822
1857
  title: "Genre not found",
1823
- content: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This genre does not exist." })
1858
+ content: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This genre does not exist." })
1824
1859
  };
1825
1860
  if (result.status === "error") return {
1826
1861
  name: null,
1827
1862
  title: "Genre unavailable",
1828
- content: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
1863
+ content: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
1829
1864
  };
1830
1865
  if (!detail || !view) return {
1831
1866
  name: null,
1832
1867
  title: "Loading genre\u2026",
1833
- content: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
1834
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.Skeleton, { className: "h-6 w-2/3" }),
1835
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.Skeleton, { className: "h-4 w-full" }),
1836
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.Skeleton, { className: "h-4 w-3/4" })
1868
+ content: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
1869
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.Skeleton, { className: "h-6 w-2/3" }),
1870
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.Skeleton, { className: "h-4 w-full" }),
1871
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.Skeleton, { className: "h-4 w-3/4" })
1837
1872
  ] })
1838
1873
  };
1839
- const selectGenre = (nodeId) => onSelectGenre(import_genre_tree20.GenreUuidSchema.parse(nodeId));
1840
- const family = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1874
+ const selectGenre = (nodeId) => onSelectGenre(import_genre_tree21.GenreUuidSchema.parse(nodeId));
1875
+ const family = /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1841
1876
  import_genre_tree_view4.GenreNodeFamily,
1842
1877
  {
1843
1878
  node: view.node,
@@ -1848,7 +1883,7 @@ function useGenreDetailContent({
1848
1883
  onSelectNode: selectGenre
1849
1884
  }
1850
1885
  );
1851
- const ancestors = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1886
+ const ancestors = /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1852
1887
  import_genre_tree_view4.GenreNodeAncestors,
1853
1888
  {
1854
1889
  node: view.node,
@@ -1863,23 +1898,23 @@ function useGenreDetailContent({
1863
1898
  title: detail.name,
1864
1899
  headerAccent: { background: view.fill, color: view.textColor },
1865
1900
  aside: expanded ? ancestors : void 0,
1866
- content: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
1867
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1901
+ content: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
1902
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1868
1903
  GenreInfoPanelBody,
1869
1904
  {
1870
- family: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
1905
+ family: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
1871
1906
  family,
1872
1907
  !expanded && ancestors
1873
1908
  ] }),
1874
1909
  genreUuid: detail.uuid,
1875
- genrePlaylist: hostPlaylist ?? (detail.criteriaPlaylist === null ? null : scope === "reference" ? { ...import_genre_tree20.GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist), criteria: import_genre_tree20.CriteriaMinimumSchema.parse(detail) } : { ...detail.criteriaPlaylist, criteria: import_genre_tree20.CriteriaMinimumSchema.parse(detail), tracksCount: detail.tracksCount }),
1910
+ genrePlaylist: hostPlaylist ?? (detail.criteriaPlaylist === null ? null : scope === "reference" ? { ...import_genre_tree21.GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist), criteria: import_genre_tree21.CriteriaMinimumSchema.parse(detail) } : { ...detail.criteriaPlaylist, criteria: import_genre_tree21.CriteriaMinimumSchema.parse(detail), tracksCount: detail.tracksCount }),
1876
1911
  catalogue: detail.catalogue,
1877
1912
  wikidataId: detail.wikidataId,
1878
1913
  scope,
1879
1914
  getBackendBaseUrl,
1880
1915
  playback,
1881
1916
  band: { node: view.node, ...band, shareTarget: band?.shareTarget?.kind === "genre" ? { ...band.shareTarget, name: detail.name } : band?.shareTarget },
1882
- extras
1917
+ extras: { ...extras, imageInCover: true }
1883
1918
  }
1884
1919
  ),
1885
1920
  trailing
@@ -1911,9 +1946,13 @@ function GenreDetailPanel({
1911
1946
  expanded,
1912
1947
  band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
1913
1948
  });
1914
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1915
- import_ui10.DetailPanel,
1949
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1950
+ GenreOverviewDetailPanel,
1916
1951
  {
1952
+ genreUuid: panel.name ? import_genre_tree21.GenreUuidSchema.parse(genreUuid) : null,
1953
+ scope,
1954
+ getBackendBaseUrl,
1955
+ criteriaOverviewSchema: extras?.criteriaOverviewSchema,
1917
1956
  side: "left",
1918
1957
  title: panel.title,
1919
1958
  headerAccent: panel.headerAccent,
@@ -1924,17 +1963,17 @@ function GenreDetailPanel({
1924
1963
  edgeTab,
1925
1964
  aside: panel.aside,
1926
1965
  titleInSearch,
1927
- headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react9.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react9.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
1966
+ headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react9.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react9.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
1928
1967
  children: panel.content
1929
1968
  }
1930
1969
  );
1931
1970
  }
1932
1971
 
1933
1972
  // src/genre-tree/ChangeParentPopup.tsx
1934
- var import_react16 = require("react");
1935
- var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
1936
- var import_ui11 = require("@behindthemusictree/ui");
1937
- var import_jsx_runtime32 = require("react/jsx-runtime");
1973
+ var import_react17 = require("react");
1974
+ var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
1975
+ var import_ui12 = require("@behindthemusictree/ui");
1976
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1938
1977
  function ChangeParentPopup({
1939
1978
  genrePlaylist,
1940
1979
  genrePlaylists,
@@ -1943,12 +1982,12 @@ function ChangeParentPopup({
1943
1982
  onClose,
1944
1983
  onParentChanged
1945
1984
  }) {
1946
- const { mutate, isPending, formErrors } = (0, import_genre_tree21.useUpdateGenre)(scope, getBackendBaseUrl);
1947
- const candidates = (0, import_react16.useMemo)(
1948
- () => (0, import_genre_tree21.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
1985
+ const { mutate, isPending, formErrors } = (0, import_genre_tree22.useUpdateGenre)(scope, getBackendBaseUrl);
1986
+ const candidates = (0, import_react17.useMemo)(
1987
+ () => (0, import_genre_tree22.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
1949
1988
  [genrePlaylists, genrePlaylist.uuid]
1950
1989
  );
1951
- const [confirmingRoot, setConfirmingRoot] = (0, import_react16.useState)(false);
1990
+ const [confirmingRoot, setConfirmingRoot] = (0, import_react17.useState)(false);
1952
1991
  const handleMove = (to) => {
1953
1992
  const genre = genrePlaylist.criteria.uuid;
1954
1993
  const parentPlaylistUuid = genrePlaylist.parent?.uuid;
@@ -1964,31 +2003,31 @@ function ChangeParentPopup({
1964
2003
  );
1965
2004
  };
1966
2005
  const handleSelect = (newParent) => handleMove(newParent.criteria.uuid);
1967
- (0, import_react16.useEffect)(() => {
2006
+ (0, import_react17.useEffect)(() => {
1968
2007
  const handleKeyDown = (event) => {
1969
2008
  if (event.key === "Escape") onClose();
1970
2009
  };
1971
2010
  window.addEventListener("keydown", handleKeyDown);
1972
2011
  return () => window.removeEventListener("keydown", handleKeyDown);
1973
2012
  }, [onClose]);
1974
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
1975
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
2013
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
2014
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
1976
2015
  "Current parent: ",
1977
2016
  genrePlaylist.parent?.name ?? "none"
1978
2017
  ] }),
1979
- genrePlaylist.parent && (confirmingRoot ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "mb-3 text-sm", children: [
1980
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("p", { className: "mb-2", children: [
2018
+ genrePlaylist.parent && (confirmingRoot ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "mb-3 text-sm", children: [
2019
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { className: "mb-2", children: [
1981
2020
  genrePlaylist.name,
1982
2021
  " and its descendants will no longer be under ",
1983
2022
  genrePlaylist.parent.name,
1984
2023
  "."
1985
2024
  ] }),
1986
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(PopupButtons, { alignment: "left", children: [
1987
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.Button, { disabled: isPending, onClick: () => handleMove(null), children: "Confirm" }),
1988
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.Button, { variant: "secondary", disabled: isPending, onClick: () => setConfirmingRoot(false), children: "Back" })
2025
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(PopupButtons, { alignment: "left", children: [
2026
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui12.Button, { disabled: isPending, onClick: () => handleMove(null), children: "Confirm" }),
2027
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui12.Button, { variant: "secondary", disabled: isPending, onClick: () => setConfirmingRoot(false), children: "Back" })
1989
2028
  ] })
1990
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.Button, { variant: "secondary", onClick: () => setConfirmingRoot(true), children: "Make root" }) })),
1991
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2029
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui12.Button, { variant: "secondary", onClick: () => setConfirmingRoot(true), children: "Make root" }) })),
2030
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1992
2031
  GenreSearch,
1993
2032
  {
1994
2033
  genrePlaylists: candidates,
@@ -1996,25 +2035,25 @@ function ChangeParentPopup({
1996
2035
  placeholder: "Search a new parent\u2026"
1997
2036
  }
1998
2037
  ) }),
1999
- formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
2038
+ formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
2000
2039
  ] });
2001
2040
  }
2002
2041
 
2003
2042
  // src/genre-tree/artist/useArtistPanel.tsx
2004
- var import_ui18 = require("@behindthemusictree/ui");
2005
- var import_genre_tree27 = require("@behindthemusictree/app-kit/genre-tree");
2043
+ var import_ui19 = require("@behindthemusictree/ui");
2044
+ var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
2006
2045
 
2007
2046
  // src/genre-tree/artist/ArtistActionBand.tsx
2008
2047
  var import_lucide_react10 = require("lucide-react");
2009
- var import_ui12 = require("@behindthemusictree/ui");
2010
- var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
2048
+ var import_ui13 = require("@behindthemusictree/ui");
2049
+ var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
2011
2050
  var import_player7 = require("@behindthemusictree/app-kit/player");
2012
- var import_jsx_runtime33 = require("react/jsx-runtime");
2051
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2013
2052
  function ArtistActionBand({ artist, share }) {
2014
- const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree22.useTrackList)();
2053
+ const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree23.useTrackList)();
2015
2054
  const { isPlaying, setIsPlaying } = (0, import_player7.usePlayer)();
2016
2055
  const origin = trackList?.origin;
2017
- const isCurrent = origin?.type === import_genre_tree22.TrackListOriginType.ARTIST && origin.uuid === artist.uuid;
2056
+ const isCurrent = origin?.type === import_genre_tree23.TrackListOriginType.ARTIST && origin.uuid === artist.uuid;
2018
2057
  const playing = isCurrent && isPlaying;
2019
2058
  const handleClick = () => {
2020
2059
  if (isCurrent) {
@@ -2025,11 +2064,11 @@ function ArtistActionBand({ artist, share }) {
2025
2064
  console.error("Failed to load artist tracks:", error);
2026
2065
  });
2027
2066
  };
2028
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui12.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ui12.ActionBand, { children: [
2029
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2030
- import_ui12.ActionButton,
2067
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui13.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_ui13.ActionBand, { children: [
2068
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2069
+ import_ui13.ActionButton,
2031
2070
  {
2032
- icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react10.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react10.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2071
+ icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react10.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react10.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2033
2072
  label: playing ? "Pause" : "Play",
2034
2073
  caption: String(artist.playableTracksCount),
2035
2074
  disabled: artist.playableTracksCount === 0,
@@ -2042,13 +2081,13 @@ function ArtistActionBand({ artist, share }) {
2042
2081
  }
2043
2082
 
2044
2083
  // src/genre-tree/artist/ArtistHeader.tsx
2045
- var import_ui14 = require("@behindthemusictree/ui");
2084
+ var import_ui15 = require("@behindthemusictree/ui");
2046
2085
 
2047
2086
  // src/genre-tree/artist/ArtistLinks.tsx
2048
2087
  var import_lucide_react11 = require("lucide-react");
2049
2088
  var import_si3 = require("react-icons/si");
2050
- var import_ui13 = require("@behindthemusictree/ui");
2051
- var import_jsx_runtime34 = require("react/jsx-runtime");
2089
+ var import_ui14 = require("@behindthemusictree/ui");
2090
+ var import_jsx_runtime35 = require("react/jsx-runtime");
2052
2091
  var LINK_KINDS = {
2053
2092
  official: { label: "Official website", Icon: import_lucide_react11.Globe },
2054
2093
  wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
@@ -2085,7 +2124,7 @@ function artistLinks(artist) {
2085
2124
  return links;
2086
2125
  }
2087
2126
  function ArtistLinks({ links }) {
2088
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui13.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
2127
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui14.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
2089
2128
  }
2090
2129
 
2091
2130
  // src/genre-tree/artist/formatYears.ts
@@ -2096,7 +2135,7 @@ function formatYears(beginYear, endYear, ended) {
2096
2135
  }
2097
2136
 
2098
2137
  // src/genre-tree/artist/ArtistHeader.tsx
2099
- var import_jsx_runtime35 = require("react/jsx-runtime");
2138
+ var import_jsx_runtime36 = require("react/jsx-runtime");
2100
2139
  var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
2101
2140
  function originLabel(artist, origin) {
2102
2141
  if (origin.source === "area") return "From";
@@ -2110,7 +2149,7 @@ function OriginValue({
2110
2149
  renderPlaceLink
2111
2150
  }) {
2112
2151
  const place = renderPlaceLink && origin.regionId !== null ? renderPlaceLink({ ...origin, regionId: origin.regionId }) : origin.name;
2113
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
2152
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
2114
2153
  place,
2115
2154
  country && origin.kind !== "country" && `, ${country}`
2116
2155
  ] });
@@ -2125,30 +2164,24 @@ function ArtistHeader({
2125
2164
  if (artist.origin) {
2126
2165
  fields.push({
2127
2166
  label: originLabel(artist, artist.origin),
2128
- value: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(OriginValue, { origin: artist.origin, country, renderPlaceLink })
2167
+ value: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(OriginValue, { origin: artist.origin, country, renderPlaceLink })
2129
2168
  });
2130
2169
  }
2131
2170
  if (country && !artist.origin) fields.push({ label: "Country", value: country });
2132
2171
  const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
2133
2172
  if (years) fields.push({ label: "Active", value: years });
2134
2173
  const links = artistLinks(artist);
2135
- if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ArtistLinks, { links }) });
2174
+ if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ArtistLinks, { links }) });
2136
2175
  if (fields.length === 0) return null;
2137
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui14.FieldList, { items: fields });
2138
- }
2139
-
2140
- // src/genre-tree/artist/ArtistPhoto.tsx
2141
- var import_jsx_runtime36 = require("react/jsx-runtime");
2142
- function ArtistPhoto({ image, name }) {
2143
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CommonsPhoto, { image, alt: name });
2176
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui15.FieldList, { items: fields });
2144
2177
  }
2145
2178
 
2146
2179
  // src/genre-tree/artist/ArtistMembers.tsx
2147
- var import_ui15 = require("@behindthemusictree/ui");
2180
+ var import_ui16 = require("@behindthemusictree/ui");
2148
2181
  var import_jsx_runtime37 = require("react/jsx-runtime");
2149
2182
  function MembershipList({ title, memberships, renderArtistLink }) {
2150
2183
  if (memberships.length === 0) return null;
2151
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { children: memberships.map((membership, index) => {
2184
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui16.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { children: memberships.map((membership, index) => {
2152
2185
  const details = [
2153
2186
  formatYears(membership.beginYear, membership.endYear, membership.ended),
2154
2187
  ...membership.roles
@@ -2169,7 +2202,7 @@ function MembershipList({ title, memberships, renderArtistLink }) {
2169
2202
  function ArtistMembers({ title, memberships, renderArtistLink }) {
2170
2203
  if (memberships.length === 0) return null;
2171
2204
  const isCurrent = (membership) => !membership.ended && membership.endYear === null;
2172
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_ui15.PanelSection, { title, children: [
2205
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_ui16.PanelSection, { title, children: [
2173
2206
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
2174
2207
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2175
2208
  MembershipList,
@@ -2183,7 +2216,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
2183
2216
  }
2184
2217
 
2185
2218
  // src/genre-tree/artist/ArtistDiscography.tsx
2186
- var import_ui16 = require("@behindthemusictree/ui");
2219
+ var import_ui17 = require("@behindthemusictree/ui");
2187
2220
  var import_jsx_runtime38 = require("react/jsx-runtime");
2188
2221
  var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
2189
2222
  var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
@@ -2204,10 +2237,10 @@ function byYear(a, b) {
2204
2237
  function ArtistDiscography({ albums }) {
2205
2238
  if (albums.length === 0) return null;
2206
2239
  const sorted = [...albums].sort(byYear);
2207
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui16.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
2240
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui17.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
2208
2241
  const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
2209
2242
  if (groupAlbums.length === 0) return null;
2210
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui16.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
2243
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui17.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
2211
2244
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
2212
2245
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
2213
2246
  ] }, album.uuid)) }) }, group);
@@ -2215,16 +2248,16 @@ function ArtistDiscography({ albums }) {
2215
2248
  }
2216
2249
 
2217
2250
  // src/genre-tree/artist/ArtistSongs.tsx
2218
- var import_react17 = require("react");
2251
+ var import_react18 = require("react");
2219
2252
  var import_react_query2 = require("@tanstack/react-query");
2220
- var import_ui17 = require("@behindthemusictree/ui");
2253
+ var import_ui18 = require("@behindthemusictree/ui");
2221
2254
  var import_player11 = require("@behindthemusictree/app-kit/player");
2222
- var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
2255
+ var import_genre_tree27 = require("@behindthemusictree/app-kit/genre-tree");
2223
2256
  var import_transport6 = require("@behindthemusictree/app-kit/transport");
2224
2257
 
2225
2258
  // src/genre-tree/track-list-sidebar/TrackItem.tsx
2226
2259
  var import_player10 = require("@behindthemusictree/app-kit/player");
2227
- var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
2260
+ var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
2228
2261
 
2229
2262
  // src/genre-tree/TrackPositionPlayPause.tsx
2230
2263
  var import_fa3 = require("react-icons/fa");
@@ -2279,8 +2312,8 @@ function TrackPositionPlayPause({
2279
2312
  }
2280
2313
 
2281
2314
  // src/genre-tree/track-list-sidebar/TrackItem.tsx
2282
- var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
2283
2315
  var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
2316
+ var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
2284
2317
  var import_jsx_runtime40 = require("react/jsx-runtime");
2285
2318
  function TrackItem({
2286
2319
  track,
@@ -2291,11 +2324,11 @@ function TrackItem({
2291
2324
  renderSongLink
2292
2325
  }) {
2293
2326
  const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = (0, import_player10.usePlayer)();
2294
- const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0, import_genre_tree23.useTrackList)();
2327
+ const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0, import_genre_tree24.useTrackList)();
2295
2328
  const scope = trackList?.origin?.scope ?? null;
2296
2329
  const isCurrentTrack = playerTrackObject?.track.id === track.uuid;
2297
2330
  const hasPlaybackError = isCurrentTrack && !!playerTrackObject?.loadError;
2298
- const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0, import_genre_tree24.isSong)(track) && (0, import_genre_tree24.songUnplayableReason)(track) !== null;
2331
+ const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0, import_genre_tree25.isSong)(track) && (0, import_genre_tree25.songUnplayableReason)(track) !== null;
2299
2332
  const handlePlayPauseClick = (event) => {
2300
2333
  event.stopPropagation();
2301
2334
  if (isCurrentTrack) {
@@ -2328,8 +2361,8 @@ function TrackItem({
2328
2361
  }
2329
2362
  ),
2330
2363
  /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
2331
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree24.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
2332
- track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree25.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
2364
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree25.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
2365
+ track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree26.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
2333
2366
  ] }),
2334
2367
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
2335
2368
  renderDuration && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
@@ -2348,20 +2381,20 @@ function TrackItem({
2348
2381
 
2349
2382
  // src/genre-tree/artist/ArtistSongs.tsx
2350
2383
  var import_jsx_runtime41 = require("react/jsx-runtime");
2351
- var SongPageSchema2 = (0, import_transport6.PaginatedResponseSchema)(import_genre_tree26.SongDetailedSchema);
2384
+ var SongPageSchema2 = (0, import_transport6.PaginatedResponseSchema)(import_genre_tree27.SongDetailedSchema);
2352
2385
  var SORTS = [
2353
2386
  { ordering: "title", label: "Title" },
2354
2387
  { ordering: "-albumYear", label: "Year" }
2355
2388
  ];
2356
2389
  function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
2357
- const [page, setPage] = (0, import_react17.useState)(1);
2358
- const [ordering, setOrdering] = (0, import_react17.useState)("title");
2359
- const { playNewTrackListFromArtist } = (0, import_genre_tree26.useTrackList)();
2390
+ const [page, setPage] = (0, import_react18.useState)(1);
2391
+ const [ordering, setOrdering] = (0, import_react18.useState)("title");
2392
+ const { playNewTrackListFromArtist } = (0, import_genre_tree27.useTrackList)();
2360
2393
  const { playerTrackObject } = (0, import_player11.usePlayer)();
2361
2394
  const { data, isPending, isError } = (0, import_transport6.usePlaybackQuery)({
2362
2395
  getBackendBaseUrl,
2363
2396
  queryKey: ["referenceSongs", "artist", artist.uuid, ordering, page],
2364
- queryFn: (fetchBound) => fetchBound(import_genre_tree26.libraryEndpoints.reference.songs.list(), true, false, void 0, {
2397
+ queryFn: (fetchBound) => fetchBound(import_genre_tree27.libraryEndpoints.reference.songs.list(), true, false, void 0, {
2365
2398
  artist: artist.uuid,
2366
2399
  ordering,
2367
2400
  page
@@ -2376,11 +2409,11 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
2376
2409
  });
2377
2410
  const handleRowClickCapture = (event, song) => {
2378
2411
  if (!(event.target instanceof Element) || !event.target.closest(".track-position-play-pause")) return;
2379
- if (playerTrackObject?.track.id === song.uuid || (0, import_genre_tree26.songUnplayableReason)(song) !== null) return;
2412
+ if (playerTrackObject?.track.id === song.uuid || (0, import_genre_tree27.songUnplayableReason)(song) !== null) return;
2380
2413
  event.stopPropagation();
2381
2414
  void play(song.uuid);
2382
2415
  };
2383
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
2416
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui18.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui18.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
2384
2417
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2385
2418
  "button",
2386
2419
  {
@@ -2404,7 +2437,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
2404
2437
  renderSongLink
2405
2438
  }
2406
2439
  ) }, song.uuid)) }),
2407
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
2440
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui18.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
2408
2441
  ] }) });
2409
2442
  }
2410
2443
 
@@ -2422,7 +2455,7 @@ function useArtistPanel({
2422
2455
  onExpandedChange,
2423
2456
  onClose
2424
2457
  }) {
2425
- const result = (0, import_genre_tree27.useArtist)(uuid, getBackendBaseUrl);
2458
+ const result = (0, import_genre_tree28.useArtist)(uuid, getBackendBaseUrl);
2426
2459
  const panel = { expanded, onExpandedChange, onClose };
2427
2460
  switch (result.status) {
2428
2461
  case "idle":
@@ -2432,12 +2465,12 @@ function useArtistPanel({
2432
2465
  ...panel,
2433
2466
  title: "Artist",
2434
2467
  content: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
2435
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-3 w-16" }),
2436
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-4 w-32" }),
2437
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-3 w-16" }),
2438
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-4 w-24" }),
2439
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-16 mt-2.5" }),
2440
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-16" })
2468
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
2469
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui19.Skeleton, { className: "h-4 w-32" }),
2470
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
2471
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui19.Skeleton, { className: "h-4 w-24" }),
2472
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui19.Skeleton, { className: "h-16 mt-2.5" }),
2473
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui19.Skeleton, { className: "h-16" })
2441
2474
  ] })
2442
2475
  };
2443
2476
  case "not-found":
@@ -2459,6 +2492,7 @@ function useArtistPanel({
2459
2492
  return {
2460
2493
  ...panel,
2461
2494
  title: artist.name,
2495
+ cover: artist.image ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CommonsCover, { image: artist.image, alt: artist.name }) : void 0,
2462
2496
  content: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
2463
2497
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2464
2498
  ArtistActionBand,
@@ -2467,7 +2501,7 @@ function useArtistPanel({
2467
2501
  share: shareTarget && shareUrl ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
2468
2502
  }
2469
2503
  ),
2470
- artist.image && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
2504
+ artist.image && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CommonsPhotoCredit, { image: artist.image }),
2471
2505
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistHeader, { artist, renderPlaceLink }),
2472
2506
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
2473
2507
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
@@ -2488,24 +2522,24 @@ function useArtistPanel({
2488
2522
  }
2489
2523
 
2490
2524
  // src/genre-tree/song/useSongPanel.tsx
2491
- var import_ui20 = require("@behindthemusictree/ui");
2492
- var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
2525
+ var import_ui21 = require("@behindthemusictree/ui");
2526
+ var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
2493
2527
 
2494
2528
  // src/genre-tree/song/SongPanelContent.tsx
2495
- var import_react18 = require("react");
2529
+ var import_react19 = require("react");
2496
2530
  var import_lucide_react12 = require("lucide-react");
2497
- var import_ui19 = require("@behindthemusictree/ui");
2531
+ var import_ui20 = require("@behindthemusictree/ui");
2498
2532
  var import_player12 = require("@behindthemusictree/app-kit/player");
2499
- var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
2533
+ var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
2500
2534
  var import_jsx_runtime43 = require("react/jsx-runtime");
2501
2535
  var numberFormat = new Intl.NumberFormat("en");
2502
2536
  var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
2503
2537
  var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
2504
2538
  function SongHistory({ uuid, getBackendBaseUrl }) {
2505
- const [open, setOpen] = (0, import_react18.useState)(false);
2506
- const history = (0, import_genre_tree28.useSongHistory)(uuid, getBackendBaseUrl, open);
2539
+ const [open, setOpen] = (0, import_react19.useState)(false);
2540
+ const history = (0, import_genre_tree29.useSongHistory)(uuid, getBackendBaseUrl, open);
2507
2541
  let body = null;
2508
- if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-10", "aria-busy": "true" });
2542
+ if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui20.Skeleton, { className: "h-10", "aria-busy": "true" });
2509
2543
  else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
2510
2544
  else if (history.status === "success")
2511
2545
  body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", { className: "py-1.5 text-body", children: [
@@ -2523,20 +2557,20 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
2523
2557
  dateFormat.format(new Date(entry.createdOn))
2524
2558
  ] })
2525
2559
  ] }, entry.uuid)) });
2526
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
2527
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui19.PANEL_LABEL_CLASS}`, children: "History" }),
2560
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui20.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
2561
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui20.PANEL_LABEL_CLASS}`, children: "History" }),
2528
2562
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "mt-1.5", children: body })
2529
2563
  ] }) });
2530
2564
  }
2531
2565
  function SongPanelContent(props) {
2532
2566
  const { song, scope, getBackendBaseUrl, shareUrl, renderArtistLink } = props;
2533
- const { playNewTrackListFromTrackUuid } = (0, import_genre_tree28.useTrackList)();
2567
+ const { playNewTrackListFromTrackUuid } = (0, import_genre_tree29.useTrackList)();
2534
2568
  const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player12.usePlayer)();
2535
- const unplayableReason = (0, import_genre_tree28.songUnplayableReason)(song);
2569
+ const unplayableReason = (0, import_genre_tree29.songUnplayableReason)(song);
2536
2570
  const isCurrent = playerTrackObject?.track.id === song.uuid;
2537
2571
  const isPlaying = isCurrent && playState === import_player12.PlayStates.PLAYING;
2538
2572
  const shareTarget = { kind: "song", uuid: song.uuid, name: song.title, scope };
2539
- const musicBrainzUrl = (0, import_genre_tree28.musicBrainzRecordingUrl)(song);
2573
+ const musicBrainzUrl = (0, import_genre_tree29.musicBrainzRecordingUrl)(song);
2540
2574
  const fields = [];
2541
2575
  if (song.genre) {
2542
2576
  const path = props.genrePath && props.genrePath.length > 0 ? props.genrePath : null;
@@ -2582,9 +2616,9 @@ function SongPanelContent(props) {
2582
2616
  value: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "flex gap-3", children: links })
2583
2617
  });
2584
2618
  return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
2585
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_ui19.ActionBand, { children: [
2619
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui20.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_ui20.ActionBand, { children: [
2586
2620
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2587
- import_ui19.ActionButton,
2621
+ import_ui20.ActionButton,
2588
2622
  {
2589
2623
  icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2590
2624
  label: isPlaying ? "Pause" : "Play",
@@ -2595,9 +2629,9 @@ function SongPanelContent(props) {
2595
2629
  ),
2596
2630
  shareUrl && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
2597
2631
  ] }) }),
2598
- song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_genre_tree28.ArtistNames, { artists: song.artists, renderArtistLink }) }),
2599
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.FieldList, { items: fields }),
2600
- song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
2632
+ song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_genre_tree29.ArtistNames, { artists: song.artists, renderArtistLink }) }),
2633
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui20.FieldList, { items: fields }),
2634
+ song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui20.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
2601
2635
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
2602
2636
  ] });
2603
2637
  }
@@ -2615,7 +2649,7 @@ function useSongPanel({
2615
2649
  onClose,
2616
2650
  ...navigation
2617
2651
  }) {
2618
- const result = (0, import_genre_tree29.useSong)(uuid, getBackendBaseUrl);
2652
+ const result = (0, import_genre_tree30.useSong)(uuid, getBackendBaseUrl);
2619
2653
  const panel = { expanded, onExpandedChange, onClose };
2620
2654
  switch (result.status) {
2621
2655
  case "idle":
@@ -2625,10 +2659,10 @@ function useSongPanel({
2625
2659
  ...panel,
2626
2660
  title: "Song",
2627
2661
  content: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
2628
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui20.Skeleton, { className: "h-3 w-16" }),
2629
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui20.Skeleton, { className: "h-4 w-32" }),
2630
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui20.Skeleton, { className: "h-3 w-16" }),
2631
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui20.Skeleton, { className: "h-4 w-24" })
2662
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui21.Skeleton, { className: "h-3 w-16" }),
2663
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui21.Skeleton, { className: "h-4 w-32" }),
2664
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui21.Skeleton, { className: "h-3 w-16" }),
2665
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui21.Skeleton, { className: "h-4 w-24" })
2632
2666
  ] })
2633
2667
  };
2634
2668
  case "not-found":
@@ -2703,14 +2737,14 @@ function useEntityPanel({
2703
2737
 
2704
2738
  // src/genre-tree/SizeMetricToggle.tsx
2705
2739
  var import_md = require("react-icons/md");
2706
- var import_ui21 = require("@behindthemusictree/ui");
2740
+ var import_ui22 = require("@behindthemusictree/ui");
2707
2741
  var import_jsx_runtime45 = require("react/jsx-runtime");
2708
2742
  function SizeMetricToggle({
2709
2743
  value,
2710
2744
  onChange
2711
2745
  }) {
2712
2746
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2713
- import_ui21.SegmentedControl,
2747
+ import_ui22.SegmentedControl,
2714
2748
  {
2715
2749
  variant: "floating",
2716
2750
  "aria-label": "Size nodes by",
@@ -2751,6 +2785,8 @@ function GenreTreeView({
2751
2785
  criteriaOverviewSchema,
2752
2786
  renderGenreDetailExtras,
2753
2787
  floatingControlsLeading,
2788
+ searchTrailingAction,
2789
+ searchFullWidthBreakpoint = "md",
2754
2790
  sizeMetric: controlledSizeMetric,
2755
2791
  onSizeMetricChange,
2756
2792
  renderArtistLink,
@@ -2788,21 +2824,21 @@ function GenreTreeView({
2788
2824
  placement = "default",
2789
2825
  ...focus
2790
2826
  }) {
2791
- const getShareUrlRef = (0, import_react19.useRef)(getShareUrl);
2827
+ const getShareUrlRef = (0, import_react20.useRef)(getShareUrl);
2792
2828
  getShareUrlRef.current = getShareUrl;
2793
- const [internalArtistUuid, setInternalArtistUuid] = (0, import_react19.useState)(null);
2829
+ const [internalArtistUuid, setInternalArtistUuid] = (0, import_react20.useState)(null);
2794
2830
  const isArtistControlled = controlledArtistUuid !== void 0;
2795
2831
  const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
2796
- const [internalSongUuid, setInternalSongUuid] = (0, import_react19.useState)(null);
2832
+ const [internalSongUuid, setInternalSongUuid] = (0, import_react20.useState)(null);
2797
2833
  const isSongControlled = controlledSongUuid !== void 0;
2798
2834
  const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
2799
2835
  const changeSong = (uuid) => {
2800
2836
  if (!isSongControlled) setInternalSongUuid(uuid);
2801
2837
  onSongUuidChange?.(uuid);
2802
2838
  };
2803
- const [internalSizeMetric, setInternalSizeMetric] = (0, import_react19.useState)("songs");
2839
+ const [internalSizeMetric, setInternalSizeMetric] = (0, import_react20.useState)("songs");
2804
2840
  const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
2805
- const deferredSizeMetric = (0, import_react19.useDeferredValue)(sizeMetric);
2841
+ const deferredSizeMetric = (0, import_react20.useDeferredValue)(sizeMetric);
2806
2842
  const changeSizeMetric = (metric) => {
2807
2843
  if (controlledSizeMetric === void 0) setInternalSizeMetric(metric);
2808
2844
  onSizeMetricChange?.(metric);
@@ -2834,7 +2870,7 @@ function GenreTreeView({
2834
2870
  allowWheelRotation: internalAllowWheelRotation,
2835
2871
  toggleWheelRotation,
2836
2872
  onNodeHover: handleNodeHover
2837
- } = (0, import_genre_tree31.useGenreTreeViewState)({
2873
+ } = (0, import_genre_tree32.useGenreTreeViewState)({
2838
2874
  scope,
2839
2875
  getBackendBaseUrl,
2840
2876
  viewMode: controlledViewMode,
@@ -2844,7 +2880,7 @@ function GenreTreeView({
2844
2880
  artistUuid
2845
2881
  });
2846
2882
  const restoreRevision = viewportRestore?.revision;
2847
- const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react19.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
2883
+ const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react20.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
2848
2884
  let restoreRootUuid = stackedRestoreOwner.rootUuid;
2849
2885
  if (stackedRestoreOwner.revision !== restoreRevision) {
2850
2886
  restoreRootUuid = selectedGenrePlaylist?.root.uuid;
@@ -2853,14 +2889,14 @@ function GenreTreeView({
2853
2889
  restoreRootUuid = selectedGenrePlaylist.root.uuid;
2854
2890
  setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });
2855
2891
  }
2856
- const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree31.genreUpdateMutationKey }) > 0;
2857
- const { mutate: updateGenre } = (0, import_genre_tree31.useUpdateGenre)(scope, getBackendBaseUrl);
2892
+ const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree32.genreUpdateMutationKey }) > 0;
2893
+ const { mutate: updateGenre } = (0, import_genre_tree32.useUpdateGenre)(scope, getBackendBaseUrl);
2858
2894
  const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;
2859
2895
  const isArtistFiltered = artistUuid !== null;
2860
2896
  const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
2861
- const artistResult = (0, import_genre_tree31.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
2897
+ const artistResult = (0, import_genre_tree32.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
2862
2898
  const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
2863
- const filterArtist = (0, import_react19.useMemo)(
2899
+ const filterArtist = (0, import_react20.useMemo)(
2864
2900
  () => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
2865
2901
  [artistUuid, filterArtistName]
2866
2902
  );
@@ -2875,14 +2911,14 @@ function GenreTreeView({
2875
2911
  if (selectedGenreUuid !== null) clearSelection();
2876
2912
  changeSong(uuid);
2877
2913
  };
2878
- const openSongRef = (0, import_react19.useRef)(openSong);
2914
+ const openSongRef = (0, import_react20.useRef)(openSong);
2879
2915
  openSongRef.current = openSong;
2880
- const resolvedRenderSongLink = (0, import_react19.useCallback)(
2916
+ const resolvedRenderSongLink = (0, import_react20.useCallback)(
2881
2917
  (song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
2882
2918
  [renderSongLink]
2883
2919
  );
2884
- const [expandedSongUuid, setExpandedSongUuid] = (0, import_react19.useState)(null);
2885
- const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react19.useState)(null);
2920
+ const [expandedSongUuid, setExpandedSongUuid] = (0, import_react20.useState)(null);
2921
+ const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react20.useState)(null);
2886
2922
  const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
2887
2923
  const songBaseUrl = getBackendBaseUrl;
2888
2924
  const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
@@ -2929,8 +2965,8 @@ function GenreTreeView({
2929
2965
  }
2930
2966
  });
2931
2967
  const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
2932
- const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react19.useState)(false);
2933
- const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react19.useState)(false);
2968
+ const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react20.useState)(false);
2969
+ const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react20.useState)(false);
2934
2970
  const isCollapsed = collapsed ?? uncontrolledCollapsed;
2935
2971
  const isExpanded = expanded ?? uncontrolledExpanded;
2936
2972
  const changeCollapsed = (next) => {
@@ -2941,30 +2977,30 @@ function GenreTreeView({
2941
2977
  setUncontrolledExpanded(next);
2942
2978
  onExpandedChange?.(next);
2943
2979
  };
2944
- (0, import_react19.useEffect)(() => {
2980
+ (0, import_react20.useEffect)(() => {
2945
2981
  setUncontrolledCollapsed(false);
2946
2982
  }, [selectedGenreUuid, artistUuid, songUuid]);
2947
- const [isWheelRevealed, setIsWheelRevealed] = (0, import_react19.useState)(false);
2983
+ const [isWheelRevealed, setIsWheelRevealed] = (0, import_react20.useState)(false);
2948
2984
  const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
2949
2985
  const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);
2950
- const [resolveStyle, setResolveStyle] = (0, import_react19.useState)(null);
2951
- const handleNodeStyleResolverChange = (0, import_react19.useCallback)(
2986
+ const [resolveStyle, setResolveStyle] = (0, import_react20.useState)(null);
2987
+ const handleNodeStyleResolverChange = (0, import_react20.useCallback)(
2952
2988
  (resolver) => setResolveStyle(() => resolver),
2953
2989
  []
2954
2990
  );
2955
- const panelRef = (0, import_react19.useRef)(null);
2956
- const obscuredInset = (0, import_ui22.useObscuredInset)(panelRef);
2991
+ const panelRef = (0, import_react20.useRef)(null);
2992
+ const obscuredInset = (0, import_ui23.useObscuredInset)(panelRef);
2957
2993
  const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
2958
2994
  const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
2959
- const treeNodes = (0, import_react19.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
2995
+ const treeNodes = (0, import_react20.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
2960
2996
  const relations = (0, import_genre_tree_view5.useGenreNodeRelations)(
2961
2997
  treeNodes,
2962
2998
  !overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
2963
2999
  resolveStyle
2964
3000
  );
2965
- const treeStyles = (0, import_react19.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
2966
- const validSelectedGenreUuid = (0, import_genre_tree30.toGenreUuid)(selectedGenreUuid);
2967
- const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: validSelectedGenreUuid, previous: null });
3001
+ const treeStyles = (0, import_react20.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
3002
+ const validSelectedGenreUuid = (0, import_genre_tree31.toGenreUuid)(selectedGenreUuid);
3003
+ const [selectionHistory, setSelectionHistory] = (0, import_react20.useState)({ current: validSelectedGenreUuid, previous: null });
2968
3004
  if (selectionHistory.current !== validSelectedGenreUuid) {
2969
3005
  setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
2970
3006
  }
@@ -2990,7 +3026,7 @@ function GenreTreeView({
2990
3026
  const handleGenreSearchZoomIn = () => {
2991
3027
  if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, "zoom-in");
2992
3028
  };
2993
- const zoomInRef = (0, import_react19.useRef)(void 0);
3029
+ const zoomInRef = (0, import_react20.useRef)(void 0);
2994
3030
  zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : void 0;
2995
3031
  const genrePlaylist = selectedGenrePlaylist;
2996
3032
  const criteria = genrePlaylist?.criteria;
@@ -3058,6 +3094,7 @@ function GenreTreeView({
3058
3094
  activePanel = {
3059
3095
  title: otherPanel.title,
3060
3096
  content: otherPanel.content,
3097
+ cover: otherPanel.cover,
3061
3098
  aside: otherPanel.extraContent,
3062
3099
  expanded: otherPanel.expanded ?? false,
3063
3100
  onExpandedChange: otherPanel.onExpandedChange,
@@ -3082,7 +3119,7 @@ function GenreTreeView({
3082
3119
  center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
3083
3120
  } : void 0;
3084
3121
  const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3085
- import_ui22.IconButton,
3122
+ import_ui23.IconButton,
3086
3123
  {
3087
3124
  "aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
3088
3125
  style: activePanel.headerAccent && { color: "inherit" },
@@ -3148,13 +3185,16 @@ function GenreTreeView({
3148
3185
  onPrevious: handlePrevious,
3149
3186
  onQueryChange: onSearchQueryChange,
3150
3187
  onFocus: onSearchFocus,
3188
+ trailingAction: searchTrailingAction,
3189
+ trailingActionBreakpoint: "md",
3190
+ fullWidthBreakpoint: searchFullWidthBreakpoint,
3151
3191
  extraGroups: extraSearchGroups
3152
3192
  }
3153
3193
  ),
3154
3194
  !isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
3155
3195
  /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("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", children: [
3156
3196
  !isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3157
- import_ui22.SegmentedControl,
3197
+ import_ui23.SegmentedControl,
3158
3198
  {
3159
3199
  "aria-label": "Tree view mode",
3160
3200
  value: viewMode,
@@ -3174,7 +3214,7 @@ function GenreTreeView({
3174
3214
  role: "group",
3175
3215
  "aria-label": "Tree display options",
3176
3216
  children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3177
- import_ui22.Button,
3217
+ import_ui23.Button,
3178
3218
  {
3179
3219
  variant: allowWheelRotation ? "default" : "outline",
3180
3220
  size: "sm",
@@ -3185,7 +3225,7 @@ function GenreTreeView({
3185
3225
  }
3186
3226
  ),
3187
3227
  !isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3188
- import_ui22.IconTextButton,
3228
+ import_ui23.IconTextButton,
3189
3229
  {
3190
3230
  icon: import_lucide_react13.Plus,
3191
3231
  text: "Add root",
@@ -3198,12 +3238,21 @@ function GenreTreeView({
3198
3238
  "div",
3199
3239
  {
3200
3240
  "data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
3201
- className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
3241
+ className: [
3242
+ "genre-tree-view relative flex flex-col h-full",
3243
+ placement === "regions" && REGIONS_CLASS,
3244
+ placement === "regions" && searchTrailingAction && "max-md:[&:has([data-detail-panel][data-collapsed=false][data-sheet=true]_[aria-label='Resize_panel'][aria-expanded=true])_.actions-container]:top-[max(var(--layout-touch-target),env(safe-area-inset-top))]",
3245
+ className2
3246
+ ].filter(Boolean).join(" "),
3202
3247
  children: [
3203
3248
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3204
3249
  "div",
3205
3250
  {
3206
- className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? "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" : "left-5 top-5"}`,
3251
+ className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? [
3252
+ "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:flex-col max-md:items-stretch",
3253
+ searchFullWidthBreakpoint === "sm" ? "max-sm:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))]" : "max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))]",
3254
+ searchTrailingAction ? "max-md:top-[max(var(--layout-panel-inset),env(safe-area-inset-top))]" : "max-md:top-[var(--layout-band-top)]"
3255
+ ].join(" ") : "left-5 top-5"}`,
3207
3256
  children: actions
3208
3257
  }
3209
3258
  ),
@@ -3333,11 +3382,16 @@ function GenreTreeView({
3333
3382
  }
3334
3383
  ) }),
3335
3384
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3336
- import_ui22.DetailPanel,
3385
+ GenreOverviewDetailPanel,
3337
3386
  {
3387
+ genreUuid: !otherPanel && genreContent.name && selectedGenreUuid ? (0, import_genre_tree31.toGenreUuid)(selectedGenreUuid) : null,
3388
+ scope,
3389
+ getBackendBaseUrl,
3390
+ criteriaOverviewSchema,
3338
3391
  ref: panelRef,
3339
3392
  side: "left",
3340
3393
  title: activePanel?.title ?? "",
3394
+ cover: activePanel?.cover,
3341
3395
  titleInSearch: !isLoading && !isError,
3342
3396
  headerAccent: activePanel?.headerAccent,
3343
3397
  headerActions: expandButton,
@@ -3363,13 +3417,13 @@ function GenreTreeView({
3363
3417
  var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
3364
3418
 
3365
3419
  // src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
3366
- var import_react20 = require("react");
3420
+ var import_react21 = require("react");
3367
3421
  var import_lucide_react15 = require("lucide-react");
3368
- var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
3369
3422
  var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
3423
+ var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
3370
3424
  var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
3371
3425
  var import_jsx_runtime47 = require("react/jsx-runtime");
3372
- var useBrowserLayoutEffect = typeof window === "undefined" ? import_react20.useEffect : import_react20.useLayoutEffect;
3426
+ var useBrowserLayoutEffect = typeof window === "undefined" ? import_react21.useEffect : import_react21.useLayoutEffect;
3373
3427
  function TrackListSidebar({
3374
3428
  className: className2 = "",
3375
3429
  renderDuration,
@@ -3381,18 +3435,18 @@ function TrackListSidebar({
3381
3435
  renderArtistLink,
3382
3436
  renderSongLink
3383
3437
  }) {
3384
- const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree32.useTrackList)();
3438
+ const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree33.useTrackList)();
3385
3439
  const trackNoun = (0, import_track_noun3.useTrackNoun)();
3386
- const trackListRef = (0, import_react20.useRef)(null);
3387
- const previousOriginRef = (0, import_react20.useRef)(trackList?.origin ?? null);
3388
- const handledAutoAdvanceRequestIdRef = (0, import_react20.useRef)(null);
3389
- const shouldFollowPlaybackRef = (0, import_react20.useRef)(true);
3390
- const programmaticScrollTopRef = (0, import_react20.useRef)(null);
3391
- const userScrollIntentRef = (0, import_react20.useRef)(false);
3392
- const userScrollIntentTimerRef = (0, import_react20.useRef)(null);
3393
- const loadMoreSentinelRef = (0, import_react20.useRef)(null);
3440
+ const trackListRef = (0, import_react21.useRef)(null);
3441
+ const previousOriginRef = (0, import_react21.useRef)(trackList?.origin ?? null);
3442
+ const handledAutoAdvanceRequestIdRef = (0, import_react21.useRef)(null);
3443
+ const shouldFollowPlaybackRef = (0, import_react21.useRef)(true);
3444
+ const programmaticScrollTopRef = (0, import_react21.useRef)(null);
3445
+ const userScrollIntentRef = (0, import_react21.useRef)(false);
3446
+ const userScrollIntentTimerRef = (0, import_react21.useRef)(null);
3447
+ const loadMoreSentinelRef = (0, import_react21.useRef)(null);
3394
3448
  const hasMore = !!trackList && trackList.nextPage !== null;
3395
- (0, import_react20.useEffect)(() => {
3449
+ (0, import_react21.useEffect)(() => {
3396
3450
  const sentinel = loadMoreSentinelRef.current;
3397
3451
  if (!hasMore || !sentinel) return;
3398
3452
  const observer = new IntersectionObserver((entries) => {
@@ -3412,11 +3466,11 @@ function TrackListSidebar({
3412
3466
  programmaticScrollTopRef.current = null;
3413
3467
  if (trackListRef.current) trackListRef.current.scrollTop = 0;
3414
3468
  }, [trackList?.origin]);
3415
- (0, import_react20.useEffect)(() => {
3469
+ (0, import_react21.useEffect)(() => {
3416
3470
  const list = trackListRef.current;
3417
3471
  if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;
3418
3472
  }, [isCollapsed]);
3419
- (0, import_react20.useEffect)(
3473
+ (0, import_react21.useEffect)(
3420
3474
  () => () => {
3421
3475
  if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);
3422
3476
  },
@@ -3484,7 +3538,7 @@ function TrackListSidebar({
3484
3538
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "name-container flex flex-col justify-center items-center text-[var(--color-text)] font-bold pr-2 max-w-[27.5rem]", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
3485
3539
  ] }),
3486
3540
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
3487
- trackList.origin.type === import_genre_tree33.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree33.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
3541
+ trackList.origin.type === import_genre_tree34.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree34.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
3488
3542
  `${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
3489
3543
  ] })
3490
3544
  ] }),
@@ -3532,16 +3586,16 @@ function TrackListSidebar({
3532
3586
  }
3533
3587
 
3534
3588
  // src/genre-tree/PlayerPanel.tsx
3535
- var import_react21 = require("react");
3589
+ var import_react22 = require("react");
3536
3590
  var import_lucide_react17 = require("lucide-react");
3537
3591
  var import_tailwind_merge = require("tailwind-merge");
3538
3592
  var import_player14 = require("@behindthemusictree/app-kit/player");
3539
- var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
3540
- var import_ui23 = require("@behindthemusictree/ui");
3593
+ var import_genre_tree36 = require("@behindthemusictree/app-kit/genre-tree");
3594
+ var import_ui24 = require("@behindthemusictree/ui");
3541
3595
 
3542
3596
  // src/genre-tree/PlayerControls.tsx
3543
3597
  var import_lucide_react16 = require("lucide-react");
3544
- var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
3598
+ var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
3545
3599
  var import_player13 = require("@behindthemusictree/app-kit/player");
3546
3600
  var import_jsx_runtime48 = require("react/jsx-runtime");
3547
3601
  function PlayerControls() {
@@ -3555,7 +3609,7 @@ function PlayerControls() {
3555
3609
  setVolume,
3556
3610
  volume
3557
3611
  } = (0, import_player13.usePlayer)();
3558
- const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree34.useTrackList)();
3612
+ const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree35.useTrackList)();
3559
3613
  const currentTime = (0, import_player13.useCurrentTime)();
3560
3614
  const isBusy = isLoading || playState === import_player13.PlayStates.LOADING;
3561
3615
  const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;
@@ -3569,7 +3623,7 @@ function PlayerControls() {
3569
3623
  className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
3570
3624
  children: [
3571
3625
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
3572
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree34.formatTime)(safeCurrentTime) }),
3626
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree35.formatTime)(safeCurrentTime) }),
3573
3627
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3574
3628
  "input",
3575
3629
  {
@@ -3584,7 +3638,7 @@ function PlayerControls() {
3584
3638
  onChange: (event) => seekTo(Number(event.currentTarget.value))
3585
3639
  }
3586
3640
  ),
3587
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree34.formatTime)(safeDuration) })
3641
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree35.formatTime)(safeDuration) })
3588
3642
  ] }),
3589
3643
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
3590
3644
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
@@ -3663,13 +3717,13 @@ function PlayerPanel({
3663
3717
  renderSongLink
3664
3718
  }) {
3665
3719
  const { playerTrackObject, retryPlayback, stop } = (0, import_player14.usePlayer)();
3666
- const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree35.useTrackListSidebarVisibility)();
3667
- const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react21.useState)("");
3720
+ const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree36.useTrackListSidebarVisibility)();
3721
+ const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react22.useState)("");
3668
3722
  const loadedTrackTitle = playerTrackObject?.track.title;
3669
- (0, import_react21.useEffect)(() => {
3723
+ (0, import_react22.useEffect)(() => {
3670
3724
  if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
3671
3725
  }, [loadedTrackTitle]);
3672
- const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react21.useState)(false);
3726
+ const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react22.useState)(false);
3673
3727
  const isExtendRequested = expanded ?? uncontrolledExtended;
3674
3728
  const setIsExtendRequested = (next) => {
3675
3729
  setUncontrolledExtended(next);
@@ -3704,7 +3758,7 @@ function PlayerPanel({
3704
3758
  style: isExtended ? { width: extendedWidth } : void 0,
3705
3759
  children: [
3706
3760
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3707
- import_ui23.PanelEdgeTab,
3761
+ import_ui24.PanelEdgeTab,
3708
3762
  {
3709
3763
  side: "right",
3710
3764
  edge: tabEdge,
@@ -3724,7 +3778,7 @@ function PlayerPanel({
3724
3778
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
3725
3779
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: [
3726
3780
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }),
3727
- playerTrackObject && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui23.IconButton, { "aria-label": "Close player", onClick: stop, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react17.X, { "aria-hidden": "true", className: "h-4 w-4" }) })
3781
+ playerTrackObject && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui24.IconButton, { "aria-label": "Close player", onClick: stop, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react17.X, { "aria-hidden": "true", className: "h-4 w-4" }) })
3728
3782
  ] }),
3729
3783
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "relative w-full shrink-0", children: [
3730
3784
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_player14.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
@@ -3763,7 +3817,7 @@ function PlayerPanel({
3763
3817
  // src/genre-tree/Rating.tsx
3764
3818
  var import_uuid = require("uuid");
3765
3819
  var import_ai = require("react-icons/ai");
3766
- var import_genre_tree36 = require("@behindthemusictree/app-kit/genre-tree");
3820
+ var import_genre_tree37 = require("@behindthemusictree/app-kit/genre-tree");
3767
3821
  var import_jsx_runtime50 = require("react/jsx-runtime");
3768
3822
  function Rating({ rating, handleChange }) {
3769
3823
  const instanceId = (0, import_uuid.v4)();
@@ -3775,7 +3829,7 @@ function Rating({ rating, handleChange }) {
3775
3829
  className: "w-6 h-6 opacity-0",
3776
3830
  type: "radio",
3777
3831
  name: "rating",
3778
- value: i === 0 ? import_genre_tree36.FORM_RATING_NULL_VALUE : i,
3832
+ value: i === 0 ? import_genre_tree37.FORM_RATING_NULL_VALUE : i,
3779
3833
  checked: rating === (i === 0 ? null : i),
3780
3834
  onChange: handleChange
3781
3835
  }
@@ -3784,7 +3838,7 @@ function Rating({ rating, handleChange }) {
3784
3838
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3785
3839
  import_ai.AiOutlineStar,
3786
3840
  {
3787
- className: `w-7 h-7 absolute top-0 left-0 ${rating === import_genre_tree36.FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
3841
+ className: `w-7 h-7 absolute top-0 left-0 ${rating === import_genre_tree37.FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
3788
3842
  }
3789
3843
  ),
3790
3844
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "flex-grow w-8" }),
@@ -3799,8 +3853,8 @@ function Rating({ rating, handleChange }) {
3799
3853
  }
3800
3854
 
3801
3855
  // src/genre-tree/EntityDetailPanel.tsx
3802
- var import_react22 = require("react");
3803
- var import_ui24 = require("@behindthemusictree/ui");
3856
+ var import_react23 = require("react");
3857
+ var import_ui25 = require("@behindthemusictree/ui");
3804
3858
  var import_jsx_runtime51 = require("react/jsx-runtime");
3805
3859
  function EntityDetailPanel({
3806
3860
  scope,
@@ -3818,8 +3872,8 @@ function EntityDetailPanel({
3818
3872
  edgeTab,
3819
3873
  ...navigation
3820
3874
  }) {
3821
- const [expandedSongUuid, setExpandedSongUuid] = (0, import_react22.useState)(null);
3822
- const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react22.useState)(null);
3875
+ const [expandedSongUuid, setExpandedSongUuid] = (0, import_react23.useState)(null);
3876
+ const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react23.useState)(null);
3823
3877
  const panel = useEntityPanel({
3824
3878
  scope,
3825
3879
  getBackendBaseUrl,
@@ -3844,10 +3898,11 @@ function EntityDetailPanel({
3844
3898
  });
3845
3899
  if (!panel) return null;
3846
3900
  return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3847
- import_ui24.DetailPanel,
3901
+ import_ui25.DetailPanel,
3848
3902
  {
3849
3903
  side: "left",
3850
3904
  title: panel.title,
3905
+ cover: panel.cover,
3851
3906
  titleInSearch: true,
3852
3907
  onClose: panel.onClose,
3853
3908
  collapsed,