@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.
package/dist/index.cjs CHANGED
@@ -589,14 +589,14 @@ function AuthCallbackHandler({ renderStatus, ...options }) {
589
589
  }
590
590
 
591
591
  // src/genre-tree/GenreTreeView.tsx
592
- var import_react19 = require("react");
592
+ var import_react20 = require("react");
593
593
  var import_react_query3 = require("@tanstack/react-query");
594
594
  var import_lucide_react17 = require("lucide-react");
595
595
  var import_lucide_react18 = require("lucide-react");
596
- var import_ui25 = require("@behindthemusictree/ui");
596
+ var import_ui26 = require("@behindthemusictree/ui");
597
597
  var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
598
- var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
599
598
  var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
599
+ var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
600
600
  var import_popup5 = require("@behindthemusictree/app-kit/popup");
601
601
 
602
602
  // src/genre-tree/playlist-tree/size-metric.ts
@@ -1049,6 +1049,8 @@ function SearchBox({
1049
1049
  onClear,
1050
1050
  clearLabel,
1051
1051
  leading,
1052
+ trailingAction,
1053
+ trailingActionBreakpoint,
1052
1054
  className: className2,
1053
1055
  onFocus
1054
1056
  }) {
@@ -1081,6 +1083,8 @@ function SearchBox({
1081
1083
  onClear,
1082
1084
  clearLabel,
1083
1085
  leading,
1086
+ trailingAction,
1087
+ trailingActionBreakpoint,
1084
1088
  inputClassName: "focus-visible:ring-0"
1085
1089
  }
1086
1090
  ) });
@@ -1181,7 +1185,10 @@ function GenreSearch({
1181
1185
  placeholder,
1182
1186
  onQueryChange,
1183
1187
  extraGroups = [],
1184
- onFocus
1188
+ onFocus,
1189
+ trailingAction,
1190
+ trailingActionBreakpoint,
1191
+ fullWidthBreakpoint = "md"
1185
1192
  }) {
1186
1193
  const { query, setQuery, results, canClear, clear, select } = (0, import_genre_tree9.useGenreSearch)({
1187
1194
  genrePlaylists,
@@ -1209,7 +1216,7 @@ function GenreSearch({
1209
1216
  (group) => active ? group : { ...group, items: [], status: "", loading: false }
1210
1217
  )
1211
1218
  ];
1212
- return /* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.jsx)(
1219
+ return /* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.jsx)(
1213
1220
  SearchBox,
1214
1221
  {
1215
1222
  label,
@@ -1230,7 +1237,9 @@ function GenreSearch({
1230
1237
  onQueryChange?.("");
1231
1238
  } : void 0,
1232
1239
  leading: onPrevious && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-label": "Previous", title: "Previous", className: import_ui7.SEARCH_LEADING_BUTTON_CLASS, onClick: onPrevious, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }) }),
1233
- onFocus
1240
+ onFocus,
1241
+ trailingAction,
1242
+ trailingActionBreakpoint
1234
1243
  }
1235
1244
  ) });
1236
1245
  }
@@ -1274,38 +1283,86 @@ function GenreTreeSearch({
1274
1283
  return SearchGroups ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SearchGroups, { query: deferredQuery, focused, onSelectGenre, children: render }) : render([]);
1275
1284
  }
1276
1285
 
1286
+ // src/genre-tree/GenreOverviewDetailPanel.tsx
1287
+ var import_react10 = require("react");
1288
+ var import_ui8 = require("@behindthemusictree/ui");
1289
+ var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
1290
+
1291
+ // src/genre-tree/CommonsPhoto.tsx
1292
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1293
+ function ExternalLink({ href, children }) {
1294
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
1295
+ }
1296
+ function CommonsPhotoCredit({ image, creditLabel = "Photo" }) {
1297
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("p", { className: "text-caption text-[var(--color-text-muted)]", children: [
1298
+ creditLabel,
1299
+ ": ",
1300
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
1301
+ ",",
1302
+ " ",
1303
+ image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
1304
+ ] });
1305
+ }
1306
+ function CommonsCover({ image, alt }) {
1307
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-cover bg-[var(--color-surface-muted)]" });
1308
+ }
1309
+ function CommonsPhoto({
1310
+ image,
1311
+ alt,
1312
+ creditLabel = "Photo"
1313
+ }) {
1314
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
1315
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
1316
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
1317
+ creditLabel,
1318
+ ": ",
1319
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
1320
+ ",",
1321
+ " ",
1322
+ image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
1323
+ ] })
1324
+ ] });
1325
+ }
1326
+
1327
+ // src/genre-tree/GenreOverviewDetailPanel.tsx
1328
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1329
+ var GenreOverviewDetailPanel = (0, import_react10.forwardRef)(function GenreOverviewDetailPanel2({ genreUuid, scope, getBackendBaseUrl, criteriaOverviewSchema, cover, ...props }, ref) {
1330
+ const { data: overview } = (0, import_genre_tree10.useFetchGenreOverview)(genreUuid, scope, getBackendBaseUrl, criteriaOverviewSchema);
1331
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ui8.DetailPanel, { ...props, ref, cover: genreUuid && overview?.image ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CommonsCover, { image: overview.image, alt: overview.name }) : cover });
1332
+ });
1333
+
1277
1334
  // src/genre-tree/GenreDetailPanel.tsx
1278
- var import_react15 = require("react");
1335
+ var import_react16 = require("react");
1279
1336
  var import_genre_tree_view4 = require("@behindthemusictree/genre-tree-view");
1280
- var import_ui13 = require("@behindthemusictree/ui");
1337
+ var import_ui14 = require("@behindthemusictree/ui");
1281
1338
  var import_lucide_react13 = require("lucide-react");
1282
- var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
1339
+ var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
1283
1340
 
1284
1341
  // src/genre-tree/GenreInfoPanelBody.tsx
1285
- var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
1342
+ var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
1286
1343
 
1287
1344
  // src/genre-tree/GenreActionBand.tsx
1288
1345
  var import_lucide_react11 = require("lucide-react");
1289
- var import_ui9 = require("@behindthemusictree/ui");
1346
+ var import_ui10 = require("@behindthemusictree/ui");
1290
1347
 
1291
1348
  // src/genre-tree/ShareActionButton.tsx
1292
1349
  var import_lucide_react10 = require("lucide-react");
1293
- var import_ui8 = require("@behindthemusictree/ui");
1350
+ var import_ui9 = require("@behindthemusictree/ui");
1294
1351
  var import_popup3 = require("@behindthemusictree/app-kit/popup");
1295
1352
 
1296
1353
  // src/genre-tree/SharePopup.tsx
1297
- var import_react10 = require("react");
1354
+ var import_react11 = require("react");
1298
1355
  var import_lucide_react9 = require("lucide-react");
1299
1356
  var import_fa3 = require("react-icons/fa");
1300
1357
  var import_si = require("react-icons/si");
1301
1358
 
1302
1359
  // src/genre-tree/ShareDestinationButton.tsx
1303
- var import_jsx_runtime23 = require("react/jsx-runtime");
1360
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1304
1361
  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";
1305
1362
  function Contents({ icon, label }) {
1306
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
1307
- /* @__PURE__ */ (0, import_jsx_runtime23.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 }),
1308
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "max-w-full truncate", children: label })
1363
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
1364
+ /* @__PURE__ */ (0, import_jsx_runtime25.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 }),
1365
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "max-w-full truncate", children: label })
1309
1366
  ] });
1310
1367
  }
1311
1368
  function ShareDestinationButton({
@@ -1317,29 +1374,29 @@ function ShareDestinationButton({
1317
1374
  ariaLabel
1318
1375
  }) {
1319
1376
  if (href) {
1320
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Contents, { icon, label }) });
1377
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Contents, { icon, label }) });
1321
1378
  }
1322
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Contents, { icon, label }) });
1379
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Contents, { icon, label }) });
1323
1380
  }
1324
1381
 
1325
1382
  // src/genre-tree/SharePreviewCard.tsx
1326
1383
  var import_lucide_react8 = require("lucide-react");
1327
- var import_jsx_runtime24 = require("react/jsx-runtime");
1384
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1328
1385
  function SharePreviewCard({ target, url }) {
1329
1386
  const Icon = { genre: import_lucide_react8.Music2, artist: import_lucide_react8.UserRound, song: import_lucide_react8.Music }[target.kind];
1330
1387
  const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
1331
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
1332
- /* @__PURE__ */ (0, import_jsx_runtime24.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_runtime24.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
1333
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
1334
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
1335
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
1336
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
1388
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
1389
+ /* @__PURE__ */ (0, import_jsx_runtime26.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_runtime26.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
1390
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
1391
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
1392
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
1393
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
1337
1394
  ] })
1338
1395
  ] }) });
1339
1396
  }
1340
1397
 
1341
1398
  // src/genre-tree/SharePopup.tsx
1342
- var import_jsx_runtime25 = require("react/jsx-runtime");
1399
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1343
1400
  function resolveAbsoluteUrl(url) {
1344
1401
  try {
1345
1402
  const parsed = new URL(url, window.location.href);
@@ -1372,20 +1429,20 @@ async function copyText(text) {
1372
1429
  }
1373
1430
  }
1374
1431
  function SharePopup({ target, url, onClose }) {
1375
- const [absoluteUrl, setAbsoluteUrl] = (0, import_react10.useState)(url);
1376
- const [copyStatus, setCopyStatus] = (0, import_react10.useState)("idle");
1377
- const [canUseNativeShare, setCanUseNativeShare] = (0, import_react10.useState)(false);
1378
- const [shareError, setShareError] = (0, import_react10.useState)(null);
1379
- const [toastId, setToastId] = (0, import_react10.useState)(0);
1380
- (0, import_react10.useEffect)(() => {
1432
+ const [absoluteUrl, setAbsoluteUrl] = (0, import_react11.useState)(url);
1433
+ const [copyStatus, setCopyStatus] = (0, import_react11.useState)("idle");
1434
+ const [canUseNativeShare, setCanUseNativeShare] = (0, import_react11.useState)(false);
1435
+ const [shareError, setShareError] = (0, import_react11.useState)(null);
1436
+ const [toastId, setToastId] = (0, import_react11.useState)(0);
1437
+ (0, import_react11.useEffect)(() => {
1381
1438
  setAbsoluteUrl(resolveAbsoluteUrl(url) ?? "");
1382
1439
  setCopyStatus("idle");
1383
1440
  setShareError(null);
1384
1441
  }, [url]);
1385
- (0, import_react10.useEffect)(() => {
1442
+ (0, import_react11.useEffect)(() => {
1386
1443
  setCanUseNativeShare(typeof navigator !== "undefined" && typeof navigator.share === "function");
1387
1444
  }, []);
1388
- const destinationUrls = (0, import_react10.useMemo)(() => {
1445
+ const destinationUrls = (0, import_react11.useMemo)(() => {
1389
1446
  if (!absoluteUrl) return null;
1390
1447
  const message = `${target.name} \u2014 ${absoluteUrl}`;
1391
1448
  return {
@@ -1403,7 +1460,7 @@ function SharePopup({ target, url, onClose }) {
1403
1460
  setCopyStatus(copied ? "idle" : "failed");
1404
1461
  if (copied) setToastId((id) => id + 1);
1405
1462
  };
1406
- const dismissToast = (0, import_react10.useCallback)(() => setToastId(0), []);
1463
+ const dismissToast = (0, import_react11.useCallback)(() => setToastId(0), []);
1407
1464
  const handleNativeShare = async () => {
1408
1465
  if (!absoluteUrl || !navigator.share) return;
1409
1466
  setShareError(null);
@@ -1414,8 +1471,8 @@ function SharePopup({ target, url, onClose }) {
1414
1471
  setShareError("Could not open the share options.");
1415
1472
  }
1416
1473
  };
1417
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
1418
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1474
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
1475
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1419
1476
  BasePopup_default,
1420
1477
  {
1421
1478
  title: "Share",
@@ -1430,70 +1487,70 @@ function SharePopup({ target, url, onClose }) {
1430
1487
  titleTextClassName: "!text-xl !font-semibold !text-[var(--color-text)]",
1431
1488
  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)]",
1432
1489
  contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
1433
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4", children: [
1434
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SharePreviewCard, { target, url: absoluteUrl || url }),
1435
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
1436
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1490
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-4", children: [
1491
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SharePreviewCard, { target, url: absoluteUrl || url }),
1492
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
1493
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1437
1494
  ShareDestinationButton,
1438
1495
  {
1439
1496
  label: "Copy Link",
1440
- icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react9.Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
1497
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react9.Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
1441
1498
  onClick: () => void handleCopy(),
1442
1499
  ariaLabel: "Copy link",
1443
1500
  disabled: !absoluteUrl
1444
1501
  }
1445
1502
  ),
1446
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1503
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1447
1504
  ShareDestinationButton,
1448
1505
  {
1449
1506
  label: "WhatsApp",
1450
- icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_fa3.FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
1507
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa3.FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
1451
1508
  href: destinationUrls?.whatsapp,
1452
1509
  ariaLabel: `Share ${target.name} via WhatsApp`,
1453
1510
  disabled: !absoluteUrl
1454
1511
  }
1455
1512
  ),
1456
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1513
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1457
1514
  ShareDestinationButton,
1458
1515
  {
1459
1516
  label: "Gmail",
1460
- icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_si.SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
1517
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_si.SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
1461
1518
  href: destinationUrls?.gmail,
1462
1519
  ariaLabel: `Email ${target.name} with Gmail`,
1463
1520
  disabled: !absoluteUrl
1464
1521
  }
1465
1522
  ),
1466
- canUseNativeShare && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1523
+ canUseNativeShare && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1467
1524
  ShareDestinationButton,
1468
1525
  {
1469
1526
  label: "More",
1470
- icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react9.Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
1527
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react9.Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
1471
1528
  onClick: () => void handleNativeShare(),
1472
1529
  ariaLabel: "More sharing options",
1473
1530
  disabled: !absoluteUrl
1474
1531
  }
1475
1532
  )
1476
1533
  ] }),
1477
- copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
1478
- shareError && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
1534
+ copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
1535
+ shareError && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
1479
1536
  ] })
1480
1537
  }
1481
1538
  ),
1482
- toastId > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
1539
+ toastId > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
1483
1540
  ] });
1484
1541
  }
1485
1542
 
1486
1543
  // src/genre-tree/ShareActionButton.tsx
1487
- var import_jsx_runtime26 = require("react/jsx-runtime");
1544
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1488
1545
  function ShareActionButton({ target, url }) {
1489
1546
  const { showPopup, hidePopup } = (0, import_popup3.usePopup)();
1490
1547
  const openSharePopup = () => {
1491
- showPopup(/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SharePopup, { target, url, onClose: hidePopup }));
1548
+ showPopup(/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SharePopup, { target, url, onClose: hidePopup }));
1492
1549
  };
1493
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1494
- import_ui8.ActionButton,
1550
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1551
+ import_ui9.ActionButton,
1495
1552
  {
1496
- icon: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react10.Share2, { "aria-hidden": "true", className: "w-5 h-5" }),
1553
+ icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react10.Share2, { "aria-hidden": "true", className: "w-5 h-5" }),
1497
1554
  label: "Share",
1498
1555
  "aria-label": `Share ${target.name}`,
1499
1556
  title: `Share ${target.name}`,
@@ -1503,7 +1560,7 @@ function ShareActionButton({ target, url }) {
1503
1560
  }
1504
1561
 
1505
1562
  // src/genre-tree/GenreActionBand.tsx
1506
- var import_jsx_runtime27 = require("react/jsx-runtime");
1563
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1507
1564
  function GenreActionBand({
1508
1565
  node,
1509
1566
  playActions,
@@ -1524,24 +1581,24 @@ function GenreActionBand({
1524
1581
  items.push({
1525
1582
  key: "zoom-in",
1526
1583
  label: "Focus",
1527
- icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
1584
+ icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react11.ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
1528
1585
  onClick: onZoomIn
1529
1586
  });
1530
1587
  }
1531
1588
  if (onAddChild) {
1532
- adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
1589
+ adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react11.Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
1533
1590
  }
1534
1591
  if (onRename) {
1535
- adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
1592
+ adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react11.Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
1536
1593
  }
1537
1594
  if (onChangeParent) {
1538
- adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
1595
+ adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react11.MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
1539
1596
  }
1540
1597
  if (onToggleSide) {
1541
1598
  adminItems.push({
1542
1599
  key: "toggle-side",
1543
1600
  label: side === "pop" ? "Make core" : "Make pop",
1544
- icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
1601
+ icon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react11.ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
1545
1602
  onClick: onToggleSide,
1546
1603
  disabled: !!toggleSideDisabledReason,
1547
1604
  title: toggleSideDisabledReason
@@ -1556,17 +1613,17 @@ function GenreActionBand({
1556
1613
  disabled: action.enabled ? !action.enabled(node) : false
1557
1614
  });
1558
1615
  }
1559
- const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui9.ActionButton, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
1616
+ const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui10.ActionButton, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
1560
1617
  if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;
1561
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui9.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1562
- import_ui9.ActionBand,
1618
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui10.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1619
+ import_ui10.ActionBand,
1563
1620
  {
1564
1621
  className: "genre-action-band",
1565
1622
  section: { title: "Admin", label: "Admin actions", children: renderItems(adminItems) },
1566
1623
  children: [
1567
1624
  playActions,
1568
1625
  renderItems(items),
1569
- shareTarget && shareUrl && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
1626
+ shareTarget && shareUrl && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
1570
1627
  ]
1571
1628
  }
1572
1629
  ) });
@@ -1574,12 +1631,12 @@ function GenreActionBand({
1574
1631
 
1575
1632
  // src/genre-tree/GenrePlayActions.tsx
1576
1633
  var import_lucide_react12 = require("lucide-react");
1577
- var import_ui10 = require("@behindthemusictree/ui");
1578
- var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
1634
+ var import_ui11 = require("@behindthemusictree/ui");
1635
+ var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
1579
1636
  var import_player4 = require("@behindthemusictree/app-kit/player");
1580
1637
 
1581
1638
  // src/genre-tree/RegionGlobeIcon.tsx
1582
- var import_react11 = require("react");
1639
+ var import_react12 = require("react");
1583
1640
 
1584
1641
  // src/genre-tree/regionGlobePaths.ts
1585
1642
  var REGION_GLOBE_PATHS = {
@@ -1590,11 +1647,11 @@ var REGION_GLOBE_PATHS = {
1590
1647
  var REGION_GLOBES = ["africa", "americas", "asia"];
1591
1648
 
1592
1649
  // src/genre-tree/RegionGlobeIcon.tsx
1593
- var import_jsx_runtime28 = require("react/jsx-runtime");
1650
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1594
1651
  var ROTATION_INTERVAL_MS = 3e3;
1595
1652
  function RegionGlobeIcon({ className: className2 }) {
1596
- const [index, setIndex] = (0, import_react11.useState)(0);
1597
- (0, import_react11.useEffect)(() => {
1653
+ const [index, setIndex] = (0, import_react12.useState)(0);
1654
+ (0, import_react12.useEffect)(() => {
1598
1655
  const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
1599
1656
  let timer;
1600
1657
  const sync = () => {
@@ -1608,51 +1665,51 @@ function RegionGlobeIcon({ className: className2 }) {
1608
1665
  clearInterval(timer);
1609
1666
  };
1610
1667
  }, []);
1611
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
1668
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
1612
1669
  }
1613
1670
 
1614
1671
  // src/genre-tree/treeMarkPath.ts
1615
1672
  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";
1616
1673
 
1617
1674
  // src/genre-tree/TreeMarkIcon.tsx
1618
- var import_jsx_runtime29 = require("react/jsx-runtime");
1675
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1619
1676
  function TreeMarkIcon({ className: className2 }) {
1620
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
1677
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
1621
1678
  }
1622
1679
 
1623
1680
  // src/genre-tree/GenrePlayActions.tsx
1624
- var import_jsx_runtime30 = require("react/jsx-runtime");
1681
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1625
1682
  function PlayIcon({ kind }) {
1626
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
1627
- kind === "tree" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1628
- kind === "map" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1629
- kind === "tree-map" && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
1630
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
1631
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
1683
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
1684
+ kind === "tree" && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1685
+ kind === "map" && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
1686
+ kind === "tree-map" && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
1687
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
1688
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
1632
1689
  ] }),
1633
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react12.Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
1690
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react12.Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
1634
1691
  ] });
1635
1692
  }
1636
1693
  function playOptions(playlist) {
1637
1694
  if (!("genreOnlyTracksCount" in playlist)) return [{ key: "all", label: "Play", icon: "play", count: playlist.tracksCount }];
1638
- const direct = { key: "direct", label: "Genre", icon: "play", selection: { coverage: "genreOnly" }, count: (0, import_genre_tree10.genreMusicCount)(playlist, { coverage: "genreOnly" }) };
1695
+ const direct = { key: "direct", label: "Genre", icon: "play", selection: { coverage: "genreOnly" }, count: (0, import_genre_tree11.genreMusicCount)(playlist, { coverage: "genreOnly" }) };
1639
1696
  const scopes = playlist.genreAndSubgenresTracksCount;
1640
1697
  const inclusive = (label, icon, subgenres) => {
1641
1698
  const selection = { coverage: "genreAndSubgenres", subgenres };
1642
- return { key: subgenres, label, icon, selection, count: (0, import_genre_tree10.genreMusicCount)(playlist, selection) };
1699
+ return { key: subgenres, label, icon, selection, count: (0, import_genre_tree11.genreMusicCount)(playlist, selection) };
1643
1700
  };
1644
1701
  return "canonical" in scopes ? [direct, inclusive("Canonical", "tree", "canonical"), inclusive("Regional", "map", "regional"), inclusive("All", "tree-map", "all")] : [direct, inclusive("All", "map", "all")];
1645
1702
  }
1646
1703
  function GenrePlayActions({ genrePlaylist, playback }) {
1647
1704
  const { isPlaying, setIsPlaying } = (0, import_player4.usePlayer)();
1648
1705
  const options = playOptions(genrePlaylist);
1649
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: options.map((option) => {
1650
- 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());
1706
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: options.map((option) => {
1707
+ 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());
1651
1708
  const playing = isCurrent && isPlaying;
1652
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1653
- import_ui10.ActionButton,
1709
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1710
+ import_ui11.ActionButton,
1654
1711
  {
1655
- icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react12.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PlayIcon, { kind: option.icon }),
1712
+ icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react12.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(PlayIcon, { kind: option.icon }),
1656
1713
  label: playing ? "Pause" : option.label,
1657
1714
  caption: String(option.count),
1658
1715
  disabled: option.count === 0,
@@ -1671,24 +1728,24 @@ function GenrePlayActions({ genrePlaylist, playback }) {
1671
1728
  }
1672
1729
 
1673
1730
  // src/genre-tree/GenreDetailExtras.tsx
1674
- var import_ui12 = require("@behindthemusictree/ui");
1675
- var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
1731
+ var import_ui13 = require("@behindthemusictree/ui");
1732
+ var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
1676
1733
 
1677
1734
  // src/genre-tree/ClampedText.tsx
1678
- var import_react12 = require("react");
1679
- var import_jsx_runtime31 = require("react/jsx-runtime");
1735
+ var import_react13 = require("react");
1736
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1680
1737
  function ClampedText({ children, className: className2 = "" }) {
1681
- const ref = (0, import_react12.useRef)(null);
1682
- const [expanded, setExpanded] = (0, import_react12.useState)(false);
1683
- const [overflows, setOverflows] = (0, import_react12.useState)(false);
1684
- (0, import_react12.useLayoutEffect)(() => {
1738
+ const ref = (0, import_react13.useRef)(null);
1739
+ const [expanded, setExpanded] = (0, import_react13.useState)(false);
1740
+ const [overflows, setOverflows] = (0, import_react13.useState)(false);
1741
+ (0, import_react13.useLayoutEffect)(() => {
1685
1742
  const element = ref.current;
1686
1743
  if (!element || expanded) return;
1687
1744
  setOverflows(element.scrollHeight > element.clientHeight);
1688
1745
  }, [children, expanded]);
1689
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
1690
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
1691
- (overflows || expanded) && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1746
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
1747
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
1748
+ (overflows || expanded) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1692
1749
  "button",
1693
1750
  {
1694
1751
  type: "button",
@@ -1701,35 +1758,12 @@ function ClampedText({ children, className: className2 = "" }) {
1701
1758
  ] });
1702
1759
  }
1703
1760
 
1704
- // src/genre-tree/CommonsPhoto.tsx
1705
- var import_jsx_runtime32 = require("react/jsx-runtime");
1706
- function ExternalLink({ href, children }) {
1707
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
1708
- }
1709
- function CommonsPhoto({
1710
- image,
1711
- alt,
1712
- creditLabel = "Photo"
1713
- }) {
1714
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
1715
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
1716
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
1717
- creditLabel,
1718
- ": ",
1719
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
1720
- ",",
1721
- " ",
1722
- image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
1723
- ] })
1724
- ] });
1725
- }
1726
-
1727
1761
  // src/genre-tree/GenrePlaylistTracks.tsx
1728
- var import_react13 = require("react");
1762
+ var import_react14 = require("react");
1729
1763
  var import_react_query = require("@tanstack/react-query");
1730
1764
  var import_zod = require("zod");
1731
1765
  var import_fa4 = require("react-icons/fa");
1732
- var import_ui11 = require("@behindthemusictree/ui");
1766
+ var import_ui12 = require("@behindthemusictree/ui");
1733
1767
  var import_auth2 = require("@behindthemusictree/app-kit/auth");
1734
1768
  var import_transport4 = require("@behindthemusictree/app-kit/transport");
1735
1769
  var import_transport5 = require("@behindthemusictree/app-kit/transport");
@@ -1738,23 +1772,23 @@ var import_player5 = require("@behindthemusictree/app-kit/player");
1738
1772
  var import_player6 = require("@behindthemusictree/app-kit/player");
1739
1773
  var import_popup4 = require("@behindthemusictree/app-kit/popup");
1740
1774
  var import_transport7 = require("@behindthemusictree/app-kit/transport");
1741
- var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
1742
1775
  var import_genre_tree13 = require("@behindthemusictree/app-kit/genre-tree");
1743
1776
  var import_genre_tree14 = require("@behindthemusictree/app-kit/genre-tree");
1744
1777
  var import_genre_tree15 = require("@behindthemusictree/app-kit/genre-tree");
1745
1778
  var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
1779
+ var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
1746
1780
 
1747
1781
  // src/genre-tree/MusicBrainzRecordingLink.tsx
1748
- var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
1749
- var import_jsx_runtime33 = require("react/jsx-runtime");
1782
+ var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
1783
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1750
1784
  function MusicBrainzRecordingLink({
1751
1785
  song,
1752
1786
  children,
1753
1787
  className: className2 = ""
1754
1788
  }) {
1755
- const url = (0, import_genre_tree11.musicBrainzRecordingUrl)(song);
1756
- if (!url) return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_jsx_runtime33.Fragment, { children });
1757
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1789
+ const url = (0, import_genre_tree12.musicBrainzRecordingUrl)(song);
1790
+ if (!url) return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_jsx_runtime34.Fragment, { children });
1791
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1758
1792
  "a",
1759
1793
  {
1760
1794
  href: url,
@@ -1769,11 +1803,11 @@ function MusicBrainzRecordingLink({
1769
1803
  }
1770
1804
 
1771
1805
  // src/genre-tree/GenrePlaylistTracks.tsx
1772
- var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
1806
+ var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
1773
1807
  var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
1774
- var import_jsx_runtime34 = require("react/jsx-runtime");
1808
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1775
1809
  var CATALOGUE_PAGE_SIZE = 100;
1776
- var SongPageSchema = (0, import_transport5.PaginatedResponseSchema)(import_genre_tree15.SongDetailedSchema).extend({
1810
+ var SongPageSchema = (0, import_transport5.PaginatedResponseSchema)(import_genre_tree16.SongDetailedSchema).extend({
1777
1811
  overallTotal: import_zod.z.number().nullable(),
1778
1812
  page: import_zod.z.number().nullable(),
1779
1813
  totalPages: import_zod.z.number().nullable()
@@ -1802,7 +1836,7 @@ function GenrePlaylistTracks({
1802
1836
  renderTracksToolbar,
1803
1837
  artist = null
1804
1838
  }) {
1805
- const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0, import_genre_tree16.useTrackList)();
1839
+ const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0, import_genre_tree17.useTrackList)();
1806
1840
  const { session, sessionRestored } = (0, import_auth2.useSession)();
1807
1841
  const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player5.usePlayer)();
1808
1842
  const { showPopup } = (0, import_popup4.usePopup)();
@@ -1812,18 +1846,18 @@ function GenrePlaylistTracks({
1812
1846
  const { fetchBound } = (0, import_transport4.usePlaybackFetch)(getBackendBaseUrl);
1813
1847
  const playback = (0, import_transport4.usePlaybackContext)();
1814
1848
  const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
1815
- 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] : []],
1849
+ 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] : []],
1816
1850
  queryFn: async ({ pageParam }) => {
1817
1851
  if (scope === "me") {
1818
1852
  if (!uuid) throw new Error("Personal genre has no playlist");
1819
1853
  return fetchGenrePlaylistTracksPage(uuid, scope, Number(pageParam));
1820
1854
  }
1821
1855
  const response = await fetchBound(
1822
- import_genre_tree14.libraryEndpoints.reference.songs.list(),
1856
+ import_genre_tree15.libraryEndpoints.reference.songs.list(),
1823
1857
  true,
1824
1858
  false,
1825
1859
  {},
1826
- { genre: genreUuid, ...(0, import_genre_tree12.genreMusicQueryParams)(selection), ...artist && { artist: artist.uuid }, pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...pageParam && { cursor: pageParam } }
1860
+ { genre: genreUuid, ...(0, import_genre_tree13.genreMusicQueryParams)(selection), ...artist && { artist: artist.uuid }, pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...pageParam && { cursor: pageParam } }
1827
1861
  );
1828
1862
  const parsed = (0, import_transport6.parseWithLog)(SongPageSchema, response, "GenrePlaylistTracks");
1829
1863
  return { tracks: parsed.results, total: parsed.overallTotal, nextPage: parsed.next ? nextCursor(parsed.next) : null };
@@ -1834,8 +1868,8 @@ function GenrePlaylistTracks({
1834
1868
  retry: (failureCount, error) => failureCount < 1 && error instanceof DOMException && error.name === "AbortError",
1835
1869
  retryDelay: 0
1836
1870
  });
1837
- const [sentinel, setSentinel] = (0, import_react13.useState)(null);
1838
- (0, import_react13.useEffect)(() => {
1871
+ const [sentinel, setSentinel] = (0, import_react14.useState)(null);
1872
+ (0, import_react14.useEffect)(() => {
1839
1873
  if (!hasNextPage || isFetchingNextPage || !sentinel) return;
1840
1874
  const observer = new IntersectionObserver((entries) => {
1841
1875
  if (entries.some((entry) => entry.isIntersecting)) {
@@ -1857,36 +1891,36 @@ function GenrePlaylistTracks({
1857
1891
  }) : 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"));
1858
1892
  started.catch((error) => {
1859
1893
  console.error("Failed to play genre playlist:", error);
1860
- if (error instanceof import_genre_tree16.TracksFailureAlreadyReportedError) return;
1861
- showPopup(/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport7.AppError ? error.code : import_transport7.ErrorCode.CLIENT_UNKNOWN }));
1894
+ if (error instanceof import_genre_tree17.TracksFailureAlreadyReportedError) return;
1895
+ showPopup(/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport7.AppError ? error.code : import_transport7.ErrorCode.CLIENT_UNKNOWN }));
1862
1896
  });
1863
1897
  };
1864
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui11.PanelSection, { title: `${(0, import_track_noun2.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { children: [
1898
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: `${(0, import_track_noun2.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
1865
1899
  renderTracksToolbar?.(),
1866
- scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui11.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { role: "alert", children: [
1900
+ scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("p", { role: "alert", children: [
1867
1901
  "Couldn't load ",
1868
1902
  trackNoun.plural,
1869
1903
  ".",
1870
1904
  " ",
1871
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
1872
- ] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
1905
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
1906
+ ] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
1873
1907
  tracks.map((track, index) => {
1874
1908
  const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
1875
1909
  const isCurrent = playerTrackObject?.track.id === track.uuid;
1876
1910
  const isPlaying = isCurrent && playState === import_player6.PlayStates.PLAYING;
1877
- const text = /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: TEXT_CELL, children: [
1878
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree15.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
1879
- track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
1880
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree17.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
1881
- track.album && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
1911
+ const text = /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: TEXT_CELL, children: [
1912
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree16.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
1913
+ track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
1914
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_genre_tree18.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
1915
+ track.album && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
1882
1916
  ] });
1883
1917
  const leading = renderSongLeading?.(track, index);
1884
1918
  const actions = renderSongActions?.(track);
1885
- const isUnplayable = (0, import_genre_tree15.isSong)(track) && (0, import_genre_tree15.songUnplayableReason)(track) !== null;
1919
+ const isUnplayable = (0, import_genre_tree16.isSong)(track) && (0, import_genre_tree16.songUnplayableReason)(track) !== null;
1886
1920
  if (isUnplayable) {
1887
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
1921
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
1888
1922
  leading,
1889
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1923
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1890
1924
  "button",
1891
1925
  {
1892
1926
  type: "button",
@@ -1894,27 +1928,27 @@ function GenrePlaylistTracks({
1894
1928
  "aria-disabled": "true",
1895
1929
  "aria-label": label,
1896
1930
  className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
1897
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_fa4.FaPlay, { size: 10 })
1931
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_fa4.FaPlay, { size: 10 })
1898
1932
  }
1899
1933
  ),
1900
1934
  text,
1901
1935
  actions
1902
1936
  ] }, track.uuid);
1903
1937
  }
1904
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
1938
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
1905
1939
  "li",
1906
1940
  {
1907
1941
  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)]" : ""}`,
1908
1942
  children: [
1909
1943
  leading,
1910
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1944
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1911
1945
  "button",
1912
1946
  {
1913
1947
  type: "button",
1914
1948
  "aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
1915
1949
  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"}`,
1916
1950
  onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
1917
- children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui11.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_fa4.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_fa4.FaPlay, { size: 10 })
1951
+ children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_fa4.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_fa4.FaPlay, { size: 10 })
1918
1952
  }
1919
1953
  ),
1920
1954
  text,
@@ -1924,7 +1958,7 @@ function GenrePlaylistTracks({
1924
1958
  track.uuid
1925
1959
  );
1926
1960
  }),
1927
- hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
1961
+ hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
1928
1962
  ] })
1929
1963
  ] }) });
1930
1964
  }
@@ -1932,8 +1966,9 @@ function GenrePlaylistTracks({
1932
1966
  // src/genre-tree/GenreDetailExtras.tsx
1933
1967
  var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
1934
1968
  var import_si2 = require("react-icons/si");
1935
- var import_jsx_runtime35 = require("react/jsx-runtime");
1969
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1936
1970
  function GenreDetailExtras({
1971
+ imageInCover = false,
1937
1972
  genreUuid,
1938
1973
  genrePlaylist,
1939
1974
  genreName,
@@ -1951,25 +1986,25 @@ function GenreDetailExtras({
1951
1986
  ...trackSlots
1952
1987
  }) {
1953
1988
  const trackNoun = (0, import_track_noun3.useTrackNoun)();
1954
- const { data: overview, isPending } = (0, import_genre_tree18.useFetchGenreOverview)(
1989
+ const { data: overview, isPending } = (0, import_genre_tree19.useFetchGenreOverview)(
1955
1990
  genreUuid,
1956
1991
  scope,
1957
1992
  getBackendBaseUrl,
1958
1993
  criteriaOverviewSchema
1959
1994
  );
1960
1995
  if (isPending) {
1961
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
1962
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.Skeleton, { className: "h-4 w-3/4" }) }) }),
1996
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
1997
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.Skeleton, { className: "h-4 w-3/4" }) }) }),
1963
1998
  family
1964
1999
  ] });
1965
2000
  }
1966
- if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_jsx_runtime35.Fragment, { children: family });
2001
+ if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_jsx_runtime36.Fragment, { children: family });
1967
2002
  const { summary, summarySourceUrl, essentialSongs, image } = overview;
1968
2003
  const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
1969
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
1970
- image && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(CommonsPhoto, { image, alt: overview.name, creditLabel: "Image" }),
1971
- (summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
1972
- summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
2004
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
2005
+ image && (imageInCover ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CommonsPhotoCredit, { image, creditLabel: "Image" }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CommonsPhoto, { image, alt: overview.name, creditLabel: "Image" })),
2006
+ (summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
2007
+ summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
1973
2008
  "a",
1974
2009
  {
1975
2010
  href: summarySourceUrl,
@@ -1977,12 +2012,12 @@ function GenreDetailExtras({
1977
2012
  rel: "noopener noreferrer",
1978
2013
  className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
1979
2014
  children: [
1980
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
2015
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1981
2016
  "Wikipedia"
1982
2017
  ]
1983
2018
  }
1984
2019
  ),
1985
- wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
2020
+ wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
1986
2021
  "a",
1987
2022
  {
1988
2023
  href: wikidataUrl,
@@ -1990,17 +2025,17 @@ function GenreDetailExtras({
1990
2025
  rel: "noopener noreferrer",
1991
2026
  className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
1992
2027
  children: [
1993
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
2028
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1994
2029
  "Wikidata"
1995
2030
  ]
1996
2031
  }
1997
2032
  )
1998
2033
  ] }) }),
1999
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
2034
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
2000
2035
  family,
2001
2036
  renderGenreDetailExtras?.(overview),
2002
- (renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
2003
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
2037
+ (renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
2038
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2004
2039
  GenrePlaylistTracks,
2005
2040
  {
2006
2041
  genreUuid,
@@ -2018,10 +2053,10 @@ function GenreDetailExtras({
2018
2053
  }
2019
2054
 
2020
2055
  // src/genre-tree/GenreInfoPanelBody.tsx
2021
- var import_jsx_runtime36 = require("react/jsx-runtime");
2022
- var import_react14 = require("react");
2056
+ var import_jsx_runtime37 = require("react/jsx-runtime");
2057
+ var import_react15 = require("react");
2023
2058
  function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
2024
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
2059
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
2025
2060
  }
2026
2061
  function GenreInfoPanelBody({
2027
2062
  toolbar,
@@ -2036,12 +2071,12 @@ function GenreInfoPanelBody({
2036
2071
  band,
2037
2072
  extras
2038
2073
  }) {
2039
- const summary = scope === "reference" ? import_genre_tree19.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
2040
- const selection = summary ? (0, import_genre_tree19.defaultGenreMusicSelection)(summary) : void 0;
2041
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
2074
+ const summary = scope === "reference" ? import_genre_tree20.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
2075
+ const selection = summary ? (0, import_genre_tree20.defaultGenreMusicSelection)(summary) : void 0;
2076
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
2042
2077
  toolbar,
2043
- genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenreActionBand, { ...band }),
2044
- /* @__PURE__ */ (0, import_react14.createElement)(
2078
+ genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(GenreActionBand, { ...band }),
2079
+ /* @__PURE__ */ (0, import_react15.createElement)(
2045
2080
  GenreDetailExtras,
2046
2081
  {
2047
2082
  ...extras,
@@ -2060,7 +2095,7 @@ function GenreInfoPanelBody({
2060
2095
  }
2061
2096
 
2062
2097
  // src/genre-tree/GenreDetailPanel.tsx
2063
- var import_jsx_runtime37 = require("react/jsx-runtime");
2098
+ var import_jsx_runtime38 = require("react/jsx-runtime");
2064
2099
  var RELATIVE_ITEM_COUNT = 1;
2065
2100
  function toNode(genre, parentId) {
2066
2101
  return {
@@ -2085,11 +2120,11 @@ function useGenreDetailContent({
2085
2120
  expanded,
2086
2121
  treeStyles
2087
2122
  }) {
2088
- const result = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
2123
+ const result = (0, import_genre_tree21.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
2089
2124
  const detail = result.status === "success" ? result.genre : void 0;
2090
2125
  const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
2091
2126
  const playback = hostPlayback ?? defaultPlayback;
2092
- const view = (0, import_react15.useMemo)(() => {
2127
+ const view = (0, import_react16.useMemo)(() => {
2093
2128
  if (!detail) return null;
2094
2129
  const rootColor = (0, import_genre_tree_view4.getGenreTreeColor)(detail.root.wikidataId);
2095
2130
  const relative = (genre, parentId) => ({
@@ -2103,7 +2138,7 @@ function useGenreDetailContent({
2103
2138
  id: detail.uuid,
2104
2139
  parentId: detail.parent?.uuid ?? null,
2105
2140
  name: detail.name,
2106
- 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,
2141
+ 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,
2107
2142
  wikidataId: detail.wikidataId
2108
2143
  },
2109
2144
  fill: own.fill,
@@ -2118,24 +2153,24 @@ function useGenreDetailContent({
2118
2153
  if (result.status === "not-found") return {
2119
2154
  name: null,
2120
2155
  title: "Genre not found",
2121
- content: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This genre does not exist." })
2156
+ content: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This genre does not exist." })
2122
2157
  };
2123
2158
  if (result.status === "error") return {
2124
2159
  name: null,
2125
2160
  title: "Genre unavailable",
2126
- content: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
2161
+ content: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
2127
2162
  };
2128
2163
  if (!detail || !view) return {
2129
2164
  name: null,
2130
2165
  title: "Loading genre\u2026",
2131
- content: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
2132
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.Skeleton, { className: "h-6 w-2/3" }),
2133
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.Skeleton, { className: "h-4 w-full" }),
2134
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.Skeleton, { className: "h-4 w-3/4" })
2166
+ content: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
2167
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.Skeleton, { className: "h-6 w-2/3" }),
2168
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.Skeleton, { className: "h-4 w-full" }),
2169
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.Skeleton, { className: "h-4 w-3/4" })
2135
2170
  ] })
2136
2171
  };
2137
- const selectGenre = (nodeId) => onSelectGenre(import_genre_tree20.GenreUuidSchema.parse(nodeId));
2138
- const family = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2172
+ const selectGenre = (nodeId) => onSelectGenre(import_genre_tree21.GenreUuidSchema.parse(nodeId));
2173
+ const family = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2139
2174
  import_genre_tree_view4.GenreNodeFamily,
2140
2175
  {
2141
2176
  node: view.node,
@@ -2146,7 +2181,7 @@ function useGenreDetailContent({
2146
2181
  onSelectNode: selectGenre
2147
2182
  }
2148
2183
  );
2149
- const ancestors = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2184
+ const ancestors = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2150
2185
  import_genre_tree_view4.GenreNodeAncestors,
2151
2186
  {
2152
2187
  node: view.node,
@@ -2161,23 +2196,23 @@ function useGenreDetailContent({
2161
2196
  title: detail.name,
2162
2197
  headerAccent: { background: view.fill, color: view.textColor },
2163
2198
  aside: expanded ? ancestors : void 0,
2164
- content: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
2165
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2199
+ content: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
2200
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2166
2201
  GenreInfoPanelBody,
2167
2202
  {
2168
- family: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
2203
+ family: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
2169
2204
  family,
2170
2205
  !expanded && ancestors
2171
2206
  ] }),
2172
2207
  genreUuid: detail.uuid,
2173
- 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 }),
2208
+ 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 }),
2174
2209
  catalogue: detail.catalogue,
2175
2210
  wikidataId: detail.wikidataId,
2176
2211
  scope,
2177
2212
  getBackendBaseUrl,
2178
2213
  playback,
2179
2214
  band: { node: view.node, ...band, shareTarget: band?.shareTarget?.kind === "genre" ? { ...band.shareTarget, name: detail.name } : band?.shareTarget },
2180
- extras
2215
+ extras: { ...extras, imageInCover: true }
2181
2216
  }
2182
2217
  ),
2183
2218
  trailing
@@ -2209,9 +2244,13 @@ function GenreDetailPanel({
2209
2244
  expanded,
2210
2245
  band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
2211
2246
  });
2212
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2213
- import_ui13.DetailPanel,
2247
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2248
+ GenreOverviewDetailPanel,
2214
2249
  {
2250
+ genreUuid: panel.name ? import_genre_tree21.GenreUuidSchema.parse(genreUuid) : null,
2251
+ scope,
2252
+ getBackendBaseUrl,
2253
+ criteriaOverviewSchema: extras?.criteriaOverviewSchema,
2215
2254
  side: "left",
2216
2255
  title: panel.title,
2217
2256
  headerAccent: panel.headerAccent,
@@ -2222,17 +2261,17 @@ function GenreDetailPanel({
2222
2261
  edgeTab,
2223
2262
  aside: panel.aside,
2224
2263
  titleInSearch,
2225
- headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react13.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react13.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
2264
+ headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react13.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react13.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
2226
2265
  children: panel.content
2227
2266
  }
2228
2267
  );
2229
2268
  }
2230
2269
 
2231
2270
  // src/genre-tree/ChangeParentPopup.tsx
2232
- var import_react16 = require("react");
2233
- var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
2234
- var import_ui14 = require("@behindthemusictree/ui");
2235
- var import_jsx_runtime38 = require("react/jsx-runtime");
2271
+ var import_react17 = require("react");
2272
+ var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
2273
+ var import_ui15 = require("@behindthemusictree/ui");
2274
+ var import_jsx_runtime39 = require("react/jsx-runtime");
2236
2275
  function ChangeParentPopup({
2237
2276
  genrePlaylist,
2238
2277
  genrePlaylists,
@@ -2241,12 +2280,12 @@ function ChangeParentPopup({
2241
2280
  onClose,
2242
2281
  onParentChanged
2243
2282
  }) {
2244
- const { mutate, isPending, formErrors } = (0, import_genre_tree21.useUpdateGenre)(scope, getBackendBaseUrl);
2245
- const candidates = (0, import_react16.useMemo)(
2246
- () => (0, import_genre_tree21.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
2283
+ const { mutate, isPending, formErrors } = (0, import_genre_tree22.useUpdateGenre)(scope, getBackendBaseUrl);
2284
+ const candidates = (0, import_react17.useMemo)(
2285
+ () => (0, import_genre_tree22.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
2247
2286
  [genrePlaylists, genrePlaylist.uuid]
2248
2287
  );
2249
- const [confirmingRoot, setConfirmingRoot] = (0, import_react16.useState)(false);
2288
+ const [confirmingRoot, setConfirmingRoot] = (0, import_react17.useState)(false);
2250
2289
  const handleMove = (to) => {
2251
2290
  const genre = genrePlaylist.criteria.uuid;
2252
2291
  const parentPlaylistUuid = genrePlaylist.parent?.uuid;
@@ -2262,31 +2301,31 @@ function ChangeParentPopup({
2262
2301
  );
2263
2302
  };
2264
2303
  const handleSelect = (newParent) => handleMove(newParent.criteria.uuid);
2265
- (0, import_react16.useEffect)(() => {
2304
+ (0, import_react17.useEffect)(() => {
2266
2305
  const handleKeyDown = (event) => {
2267
2306
  if (event.key === "Escape") onClose();
2268
2307
  };
2269
2308
  window.addEventListener("keydown", handleKeyDown);
2270
2309
  return () => window.removeEventListener("keydown", handleKeyDown);
2271
2310
  }, [onClose]);
2272
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
2273
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
2311
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
2312
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
2274
2313
  "Current parent: ",
2275
2314
  genrePlaylist.parent?.name ?? "none"
2276
2315
  ] }),
2277
- genrePlaylist.parent && (confirmingRoot ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "mb-3 text-sm", children: [
2278
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "mb-2", children: [
2316
+ genrePlaylist.parent && (confirmingRoot ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "mb-3 text-sm", children: [
2317
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "mb-2", children: [
2279
2318
  genrePlaylist.name,
2280
2319
  " and its descendants will no longer be under ",
2281
2320
  genrePlaylist.parent.name,
2282
2321
  "."
2283
2322
  ] }),
2284
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(PopupButtons, { alignment: "left", children: [
2285
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.Button, { disabled: isPending, onClick: () => handleMove(null), children: "Confirm" }),
2286
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.Button, { variant: "secondary", disabled: isPending, onClick: () => setConfirmingRoot(false), children: "Back" })
2323
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(PopupButtons, { alignment: "left", children: [
2324
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ui15.Button, { disabled: isPending, onClick: () => handleMove(null), children: "Confirm" }),
2325
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ui15.Button, { variant: "secondary", disabled: isPending, onClick: () => setConfirmingRoot(false), children: "Back" })
2287
2326
  ] })
2288
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.Button, { variant: "secondary", onClick: () => setConfirmingRoot(true), children: "Make root" }) })),
2289
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2327
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ui15.Button, { variant: "secondary", onClick: () => setConfirmingRoot(true), children: "Make root" }) })),
2328
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2290
2329
  GenreSearch,
2291
2330
  {
2292
2331
  genrePlaylists: candidates,
@@ -2294,25 +2333,25 @@ function ChangeParentPopup({
2294
2333
  placeholder: "Search a new parent\u2026"
2295
2334
  }
2296
2335
  ) }),
2297
- formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
2336
+ formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
2298
2337
  ] });
2299
2338
  }
2300
2339
 
2301
2340
  // src/genre-tree/artist/useArtistPanel.tsx
2302
- var import_ui21 = require("@behindthemusictree/ui");
2303
- var import_genre_tree27 = require("@behindthemusictree/app-kit/genre-tree");
2341
+ var import_ui22 = require("@behindthemusictree/ui");
2342
+ var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
2304
2343
 
2305
2344
  // src/genre-tree/artist/ArtistActionBand.tsx
2306
2345
  var import_lucide_react14 = require("lucide-react");
2307
- var import_ui15 = require("@behindthemusictree/ui");
2308
- var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
2346
+ var import_ui16 = require("@behindthemusictree/ui");
2347
+ var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
2309
2348
  var import_player7 = require("@behindthemusictree/app-kit/player");
2310
- var import_jsx_runtime39 = require("react/jsx-runtime");
2349
+ var import_jsx_runtime40 = require("react/jsx-runtime");
2311
2350
  function ArtistActionBand({ artist, share }) {
2312
- const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree22.useTrackList)();
2351
+ const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree23.useTrackList)();
2313
2352
  const { isPlaying, setIsPlaying } = (0, import_player7.usePlayer)();
2314
2353
  const origin = trackList?.origin;
2315
- const isCurrent = origin?.type === import_genre_tree22.TrackListOriginType.ARTIST && origin.uuid === artist.uuid;
2354
+ const isCurrent = origin?.type === import_genre_tree23.TrackListOriginType.ARTIST && origin.uuid === artist.uuid;
2316
2355
  const playing = isCurrent && isPlaying;
2317
2356
  const handleClick = () => {
2318
2357
  if (isCurrent) {
@@ -2323,11 +2362,11 @@ function ArtistActionBand({ artist, share }) {
2323
2362
  console.error("Failed to load artist tracks:", error);
2324
2363
  });
2325
2364
  };
2326
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ui15.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_ui15.ActionBand, { children: [
2327
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2328
- import_ui15.ActionButton,
2365
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_ui16.ActionBand, { children: [
2366
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2367
+ import_ui16.ActionButton,
2329
2368
  {
2330
- icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react14.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react14.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2369
+ icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react14.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react14.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2331
2370
  label: playing ? "Pause" : "Play",
2332
2371
  caption: String(artist.playableTracksCount),
2333
2372
  disabled: artist.playableTracksCount === 0,
@@ -2340,13 +2379,13 @@ function ArtistActionBand({ artist, share }) {
2340
2379
  }
2341
2380
 
2342
2381
  // src/genre-tree/artist/ArtistHeader.tsx
2343
- var import_ui17 = require("@behindthemusictree/ui");
2382
+ var import_ui18 = require("@behindthemusictree/ui");
2344
2383
 
2345
2384
  // src/genre-tree/artist/ArtistLinks.tsx
2346
2385
  var import_lucide_react15 = require("lucide-react");
2347
2386
  var import_si3 = require("react-icons/si");
2348
- var import_ui16 = require("@behindthemusictree/ui");
2349
- var import_jsx_runtime40 = require("react/jsx-runtime");
2387
+ var import_ui17 = require("@behindthemusictree/ui");
2388
+ var import_jsx_runtime41 = require("react/jsx-runtime");
2350
2389
  var LINK_KINDS = {
2351
2390
  official: { label: "Official website", Icon: import_lucide_react15.Globe },
2352
2391
  wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
@@ -2383,7 +2422,7 @@ function artistLinks(artist) {
2383
2422
  return links;
2384
2423
  }
2385
2424
  function ArtistLinks({ links }) {
2386
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
2425
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
2387
2426
  }
2388
2427
 
2389
2428
  // src/genre-tree/artist/formatYears.ts
@@ -2394,7 +2433,7 @@ function formatYears(beginYear, endYear, ended) {
2394
2433
  }
2395
2434
 
2396
2435
  // src/genre-tree/artist/ArtistHeader.tsx
2397
- var import_jsx_runtime41 = require("react/jsx-runtime");
2436
+ var import_jsx_runtime42 = require("react/jsx-runtime");
2398
2437
  var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
2399
2438
  function originLabel(artist, origin) {
2400
2439
  if (origin.source === "area") return "From";
@@ -2408,7 +2447,7 @@ function OriginValue({
2408
2447
  renderPlaceLink
2409
2448
  }) {
2410
2449
  const place = renderPlaceLink && origin.regionId !== null ? renderPlaceLink({ ...origin, regionId: origin.regionId }) : origin.name;
2411
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
2450
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
2412
2451
  place,
2413
2452
  country && origin.kind !== "country" && `, ${country}`
2414
2453
  ] });
@@ -2423,30 +2462,24 @@ function ArtistHeader({
2423
2462
  if (artist.origin) {
2424
2463
  fields.push({
2425
2464
  label: originLabel(artist, artist.origin),
2426
- value: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(OriginValue, { origin: artist.origin, country, renderPlaceLink })
2465
+ value: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(OriginValue, { origin: artist.origin, country, renderPlaceLink })
2427
2466
  });
2428
2467
  }
2429
2468
  if (country && !artist.origin) fields.push({ label: "Country", value: country });
2430
2469
  const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
2431
2470
  if (years) fields.push({ label: "Active", value: years });
2432
2471
  const links = artistLinks(artist);
2433
- if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistLinks, { links }) });
2472
+ if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistLinks, { links }) });
2434
2473
  if (fields.length === 0) return null;
2435
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.FieldList, { items: fields });
2436
- }
2437
-
2438
- // src/genre-tree/artist/ArtistPhoto.tsx
2439
- var import_jsx_runtime42 = require("react/jsx-runtime");
2440
- function ArtistPhoto({ image, name }) {
2441
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CommonsPhoto, { image, alt: name });
2474
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.FieldList, { items: fields });
2442
2475
  }
2443
2476
 
2444
2477
  // src/genre-tree/artist/ArtistMembers.tsx
2445
- var import_ui18 = require("@behindthemusictree/ui");
2478
+ var import_ui19 = require("@behindthemusictree/ui");
2446
2479
  var import_jsx_runtime43 = require("react/jsx-runtime");
2447
2480
  function MembershipList({ title, memberships, renderArtistLink }) {
2448
2481
  if (memberships.length === 0) return null;
2449
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: memberships.map((membership, index) => {
2482
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: memberships.map((membership, index) => {
2450
2483
  const details = [
2451
2484
  formatYears(membership.beginYear, membership.endYear, membership.ended),
2452
2485
  ...membership.roles
@@ -2467,7 +2500,7 @@ function MembershipList({ title, memberships, renderArtistLink }) {
2467
2500
  function ArtistMembers({ title, memberships, renderArtistLink }) {
2468
2501
  if (memberships.length === 0) return null;
2469
2502
  const isCurrent = (membership) => !membership.ended && membership.endYear === null;
2470
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_ui18.PanelSection, { title, children: [
2503
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_ui19.PanelSection, { title, children: [
2471
2504
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
2472
2505
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2473
2506
  MembershipList,
@@ -2481,7 +2514,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
2481
2514
  }
2482
2515
 
2483
2516
  // src/genre-tree/artist/ArtistDiscography.tsx
2484
- var import_ui19 = require("@behindthemusictree/ui");
2517
+ var import_ui20 = require("@behindthemusictree/ui");
2485
2518
  var import_jsx_runtime44 = require("react/jsx-runtime");
2486
2519
  var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
2487
2520
  var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
@@ -2502,10 +2535,10 @@ function byYear(a, b) {
2502
2535
  function ArtistDiscography({ albums }) {
2503
2536
  if (albums.length === 0) return null;
2504
2537
  const sorted = [...albums].sort(byYear);
2505
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui19.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
2538
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui20.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
2506
2539
  const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
2507
2540
  if (groupAlbums.length === 0) return null;
2508
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui19.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
2541
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui20.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
2509
2542
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
2510
2543
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
2511
2544
  ] }, album.uuid)) }) }, group);
@@ -2513,16 +2546,16 @@ function ArtistDiscography({ albums }) {
2513
2546
  }
2514
2547
 
2515
2548
  // src/genre-tree/artist/ArtistSongs.tsx
2516
- var import_react17 = require("react");
2549
+ var import_react18 = require("react");
2517
2550
  var import_react_query2 = require("@tanstack/react-query");
2518
- var import_ui20 = require("@behindthemusictree/ui");
2551
+ var import_ui21 = require("@behindthemusictree/ui");
2519
2552
  var import_player11 = require("@behindthemusictree/app-kit/player");
2520
- var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
2553
+ var import_genre_tree27 = require("@behindthemusictree/app-kit/genre-tree");
2521
2554
  var import_transport8 = require("@behindthemusictree/app-kit/transport");
2522
2555
 
2523
2556
  // src/genre-tree/track-list-sidebar/TrackItem.tsx
2524
2557
  var import_player10 = require("@behindthemusictree/app-kit/player");
2525
- var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
2558
+ var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
2526
2559
 
2527
2560
  // src/genre-tree/TrackPositionPlayPause.tsx
2528
2561
  var import_fa5 = require("react-icons/fa");
@@ -2577,8 +2610,8 @@ function TrackPositionPlayPause({
2577
2610
  }
2578
2611
 
2579
2612
  // src/genre-tree/track-list-sidebar/TrackItem.tsx
2580
- var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
2581
2613
  var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
2614
+ var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
2582
2615
  var import_jsx_runtime46 = require("react/jsx-runtime");
2583
2616
  function TrackItem({
2584
2617
  track,
@@ -2589,11 +2622,11 @@ function TrackItem({
2589
2622
  renderSongLink
2590
2623
  }) {
2591
2624
  const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = (0, import_player10.usePlayer)();
2592
- const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0, import_genre_tree23.useTrackList)();
2625
+ const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0, import_genre_tree24.useTrackList)();
2593
2626
  const scope = trackList?.origin?.scope ?? null;
2594
2627
  const isCurrentTrack = playerTrackObject?.track.id === track.uuid;
2595
2628
  const hasPlaybackError = isCurrentTrack && !!playerTrackObject?.loadError;
2596
- const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0, import_genre_tree24.isSong)(track) && (0, import_genre_tree24.songUnplayableReason)(track) !== null;
2629
+ const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0, import_genre_tree25.isSong)(track) && (0, import_genre_tree25.songUnplayableReason)(track) !== null;
2597
2630
  const handlePlayPauseClick = (event) => {
2598
2631
  event.stopPropagation();
2599
2632
  if (isCurrentTrack) {
@@ -2626,8 +2659,8 @@ function TrackItem({
2626
2659
  }
2627
2660
  ),
2628
2661
  /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
2629
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.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_runtime46.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
2630
- track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_genre_tree25.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
2662
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.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_runtime46.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
2663
+ track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_genre_tree26.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
2631
2664
  ] }),
2632
2665
  /* @__PURE__ */ (0, import_jsx_runtime46.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_runtime46.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
2633
2666
  renderDuration && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
@@ -2646,20 +2679,20 @@ function TrackItem({
2646
2679
 
2647
2680
  // src/genre-tree/artist/ArtistSongs.tsx
2648
2681
  var import_jsx_runtime47 = require("react/jsx-runtime");
2649
- var SongPageSchema2 = (0, import_transport8.PaginatedResponseSchema)(import_genre_tree26.SongDetailedSchema);
2682
+ var SongPageSchema2 = (0, import_transport8.PaginatedResponseSchema)(import_genre_tree27.SongDetailedSchema);
2650
2683
  var SORTS = [
2651
2684
  { ordering: "title", label: "Title" },
2652
2685
  { ordering: "-albumYear", label: "Year" }
2653
2686
  ];
2654
2687
  function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
2655
- const [page, setPage] = (0, import_react17.useState)(1);
2656
- const [ordering, setOrdering] = (0, import_react17.useState)("title");
2657
- const { playNewTrackListFromArtist } = (0, import_genre_tree26.useTrackList)();
2688
+ const [page, setPage] = (0, import_react18.useState)(1);
2689
+ const [ordering, setOrdering] = (0, import_react18.useState)("title");
2690
+ const { playNewTrackListFromArtist } = (0, import_genre_tree27.useTrackList)();
2658
2691
  const { playerTrackObject } = (0, import_player11.usePlayer)();
2659
2692
  const { data, isPending, isError } = (0, import_transport8.usePlaybackQuery)({
2660
2693
  getBackendBaseUrl,
2661
2694
  queryKey: ["referenceSongs", "artist", artist.uuid, ordering, page],
2662
- queryFn: (fetchBound) => fetchBound(import_genre_tree26.libraryEndpoints.reference.songs.list(), true, false, void 0, {
2695
+ queryFn: (fetchBound) => fetchBound(import_genre_tree27.libraryEndpoints.reference.songs.list(), true, false, void 0, {
2663
2696
  artist: artist.uuid,
2664
2697
  ordering,
2665
2698
  page
@@ -2674,11 +2707,11 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
2674
2707
  });
2675
2708
  const handleRowClickCapture = (event, song) => {
2676
2709
  if (!(event.target instanceof Element) || !event.target.closest(".track-position-play-pause")) return;
2677
- if (playerTrackObject?.track.id === song.uuid || (0, import_genre_tree26.songUnplayableReason)(song) !== null) return;
2710
+ if (playerTrackObject?.track.id === song.uuid || (0, import_genre_tree27.songUnplayableReason)(song) !== null) return;
2678
2711
  event.stopPropagation();
2679
2712
  void play(song.uuid);
2680
2713
  };
2681
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
2714
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui21.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui21.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
2682
2715
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2683
2716
  "button",
2684
2717
  {
@@ -2702,7 +2735,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
2702
2735
  renderSongLink
2703
2736
  }
2704
2737
  ) }, song.uuid)) }),
2705
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
2738
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui21.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
2706
2739
  ] }) });
2707
2740
  }
2708
2741
 
@@ -2720,7 +2753,7 @@ function useArtistPanel({
2720
2753
  onExpandedChange,
2721
2754
  onClose
2722
2755
  }) {
2723
- const result = (0, import_genre_tree27.useArtist)(uuid, getBackendBaseUrl);
2756
+ const result = (0, import_genre_tree28.useArtist)(uuid, getBackendBaseUrl);
2724
2757
  const panel = { expanded, onExpandedChange, onClose };
2725
2758
  switch (result.status) {
2726
2759
  case "idle":
@@ -2730,12 +2763,12 @@ function useArtistPanel({
2730
2763
  ...panel,
2731
2764
  title: "Artist",
2732
2765
  content: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
2733
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.Skeleton, { className: "h-3 w-16" }),
2734
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.Skeleton, { className: "h-4 w-32" }),
2735
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.Skeleton, { className: "h-3 w-16" }),
2736
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.Skeleton, { className: "h-4 w-24" }),
2737
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.Skeleton, { className: "h-16 mt-2.5" }),
2738
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.Skeleton, { className: "h-16" })
2766
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui22.Skeleton, { className: "h-3 w-16" }),
2767
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui22.Skeleton, { className: "h-4 w-32" }),
2768
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui22.Skeleton, { className: "h-3 w-16" }),
2769
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui22.Skeleton, { className: "h-4 w-24" }),
2770
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui22.Skeleton, { className: "h-16 mt-2.5" }),
2771
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui22.Skeleton, { className: "h-16" })
2739
2772
  ] })
2740
2773
  };
2741
2774
  case "not-found":
@@ -2757,6 +2790,7 @@ function useArtistPanel({
2757
2790
  return {
2758
2791
  ...panel,
2759
2792
  title: artist.name,
2793
+ cover: artist.image ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(CommonsCover, { image: artist.image, alt: artist.name }) : void 0,
2760
2794
  content: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
2761
2795
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2762
2796
  ArtistActionBand,
@@ -2765,7 +2799,7 @@ function useArtistPanel({
2765
2799
  share: shareTarget && shareUrl ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
2766
2800
  }
2767
2801
  ),
2768
- artist.image && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
2802
+ artist.image && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(CommonsPhotoCredit, { image: artist.image }),
2769
2803
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistHeader, { artist, renderPlaceLink }),
2770
2804
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
2771
2805
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
@@ -2786,24 +2820,24 @@ function useArtistPanel({
2786
2820
  }
2787
2821
 
2788
2822
  // src/genre-tree/song/useSongPanel.tsx
2789
- var import_ui23 = require("@behindthemusictree/ui");
2790
- var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
2823
+ var import_ui24 = require("@behindthemusictree/ui");
2824
+ var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
2791
2825
 
2792
2826
  // src/genre-tree/song/SongPanelContent.tsx
2793
- var import_react18 = require("react");
2827
+ var import_react19 = require("react");
2794
2828
  var import_lucide_react16 = require("lucide-react");
2795
- var import_ui22 = require("@behindthemusictree/ui");
2829
+ var import_ui23 = require("@behindthemusictree/ui");
2796
2830
  var import_player12 = require("@behindthemusictree/app-kit/player");
2797
- var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
2831
+ var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
2798
2832
  var import_jsx_runtime49 = require("react/jsx-runtime");
2799
2833
  var numberFormat = new Intl.NumberFormat("en");
2800
2834
  var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
2801
2835
  var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
2802
2836
  function SongHistory({ uuid, getBackendBaseUrl }) {
2803
- const [open, setOpen] = (0, import_react18.useState)(false);
2804
- const history = (0, import_genre_tree28.useSongHistory)(uuid, getBackendBaseUrl, open);
2837
+ const [open, setOpen] = (0, import_react19.useState)(false);
2838
+ const history = (0, import_genre_tree29.useSongHistory)(uuid, getBackendBaseUrl, open);
2805
2839
  let body = null;
2806
- if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.Skeleton, { className: "h-10", "aria-busy": "true" });
2840
+ if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui23.Skeleton, { className: "h-10", "aria-busy": "true" });
2807
2841
  else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
2808
2842
  else if (history.status === "success")
2809
2843
  body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { className: "py-1.5 text-body", children: [
@@ -2821,20 +2855,20 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
2821
2855
  dateFormat.format(new Date(entry.createdOn))
2822
2856
  ] })
2823
2857
  ] }, entry.uuid)) });
2824
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
2825
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui22.PANEL_LABEL_CLASS}`, children: "History" }),
2858
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui23.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
2859
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui23.PANEL_LABEL_CLASS}`, children: "History" }),
2826
2860
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "mt-1.5", children: body })
2827
2861
  ] }) });
2828
2862
  }
2829
2863
  function SongPanelContent(props) {
2830
2864
  const { song, scope, getBackendBaseUrl, shareUrl, renderArtistLink } = props;
2831
- const { playNewTrackListFromTrackUuid } = (0, import_genre_tree28.useTrackList)();
2865
+ const { playNewTrackListFromTrackUuid } = (0, import_genre_tree29.useTrackList)();
2832
2866
  const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player12.usePlayer)();
2833
- const unplayableReason = (0, import_genre_tree28.songUnplayableReason)(song);
2867
+ const unplayableReason = (0, import_genre_tree29.songUnplayableReason)(song);
2834
2868
  const isCurrent = playerTrackObject?.track.id === song.uuid;
2835
2869
  const isPlaying = isCurrent && playState === import_player12.PlayStates.PLAYING;
2836
2870
  const shareTarget = { kind: "song", uuid: song.uuid, name: song.title, scope };
2837
- const musicBrainzUrl = (0, import_genre_tree28.musicBrainzRecordingUrl)(song);
2871
+ const musicBrainzUrl = (0, import_genre_tree29.musicBrainzRecordingUrl)(song);
2838
2872
  const fields = [];
2839
2873
  if (song.genre) {
2840
2874
  const path = props.genrePath && props.genrePath.length > 0 ? props.genrePath : null;
@@ -2880,9 +2914,9 @@ function SongPanelContent(props) {
2880
2914
  value: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "flex gap-3", children: links })
2881
2915
  });
2882
2916
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
2883
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_ui22.ActionBand, { children: [
2917
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui23.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_ui23.ActionBand, { children: [
2884
2918
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2885
- import_ui22.ActionButton,
2919
+ import_ui23.ActionButton,
2886
2920
  {
2887
2921
  icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react16.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react16.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2888
2922
  label: isPlaying ? "Pause" : "Play",
@@ -2893,9 +2927,9 @@ function SongPanelContent(props) {
2893
2927
  ),
2894
2928
  shareUrl && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
2895
2929
  ] }) }),
2896
- song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_genre_tree28.ArtistNames, { artists: song.artists, renderArtistLink }) }),
2897
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.FieldList, { items: fields }),
2898
- song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
2930
+ song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_genre_tree29.ArtistNames, { artists: song.artists, renderArtistLink }) }),
2931
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui23.FieldList, { items: fields }),
2932
+ song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui23.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
2899
2933
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
2900
2934
  ] });
2901
2935
  }
@@ -2913,7 +2947,7 @@ function useSongPanel({
2913
2947
  onClose,
2914
2948
  ...navigation
2915
2949
  }) {
2916
- const result = (0, import_genre_tree29.useSong)(uuid, getBackendBaseUrl);
2950
+ const result = (0, import_genre_tree30.useSong)(uuid, getBackendBaseUrl);
2917
2951
  const panel = { expanded, onExpandedChange, onClose };
2918
2952
  switch (result.status) {
2919
2953
  case "idle":
@@ -2923,10 +2957,10 @@ function useSongPanel({
2923
2957
  ...panel,
2924
2958
  title: "Song",
2925
2959
  content: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
2926
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui23.Skeleton, { className: "h-3 w-16" }),
2927
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui23.Skeleton, { className: "h-4 w-32" }),
2928
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui23.Skeleton, { className: "h-3 w-16" }),
2929
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui23.Skeleton, { className: "h-4 w-24" })
2960
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui24.Skeleton, { className: "h-3 w-16" }),
2961
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui24.Skeleton, { className: "h-4 w-32" }),
2962
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui24.Skeleton, { className: "h-3 w-16" }),
2963
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui24.Skeleton, { className: "h-4 w-24" })
2930
2964
  ] })
2931
2965
  };
2932
2966
  case "not-found":
@@ -3001,14 +3035,14 @@ function useEntityPanel({
3001
3035
 
3002
3036
  // src/genre-tree/SizeMetricToggle.tsx
3003
3037
  var import_md2 = require("react-icons/md");
3004
- var import_ui24 = require("@behindthemusictree/ui");
3038
+ var import_ui25 = require("@behindthemusictree/ui");
3005
3039
  var import_jsx_runtime51 = require("react/jsx-runtime");
3006
3040
  function SizeMetricToggle({
3007
3041
  value,
3008
3042
  onChange
3009
3043
  }) {
3010
3044
  return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3011
- import_ui24.SegmentedControl,
3045
+ import_ui25.SegmentedControl,
3012
3046
  {
3013
3047
  variant: "floating",
3014
3048
  "aria-label": "Size nodes by",
@@ -3049,6 +3083,8 @@ function GenreTreeView({
3049
3083
  criteriaOverviewSchema,
3050
3084
  renderGenreDetailExtras,
3051
3085
  floatingControlsLeading,
3086
+ searchTrailingAction,
3087
+ searchFullWidthBreakpoint = "md",
3052
3088
  sizeMetric: controlledSizeMetric,
3053
3089
  onSizeMetricChange,
3054
3090
  renderArtistLink,
@@ -3086,21 +3122,21 @@ function GenreTreeView({
3086
3122
  placement = "default",
3087
3123
  ...focus
3088
3124
  }) {
3089
- const getShareUrlRef = (0, import_react19.useRef)(getShareUrl);
3125
+ const getShareUrlRef = (0, import_react20.useRef)(getShareUrl);
3090
3126
  getShareUrlRef.current = getShareUrl;
3091
- const [internalArtistUuid, setInternalArtistUuid] = (0, import_react19.useState)(null);
3127
+ const [internalArtistUuid, setInternalArtistUuid] = (0, import_react20.useState)(null);
3092
3128
  const isArtistControlled = controlledArtistUuid !== void 0;
3093
3129
  const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
3094
- const [internalSongUuid, setInternalSongUuid] = (0, import_react19.useState)(null);
3130
+ const [internalSongUuid, setInternalSongUuid] = (0, import_react20.useState)(null);
3095
3131
  const isSongControlled = controlledSongUuid !== void 0;
3096
3132
  const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
3097
3133
  const changeSong = (uuid) => {
3098
3134
  if (!isSongControlled) setInternalSongUuid(uuid);
3099
3135
  onSongUuidChange?.(uuid);
3100
3136
  };
3101
- const [internalSizeMetric, setInternalSizeMetric] = (0, import_react19.useState)("songs");
3137
+ const [internalSizeMetric, setInternalSizeMetric] = (0, import_react20.useState)("songs");
3102
3138
  const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
3103
- const deferredSizeMetric = (0, import_react19.useDeferredValue)(sizeMetric);
3139
+ const deferredSizeMetric = (0, import_react20.useDeferredValue)(sizeMetric);
3104
3140
  const changeSizeMetric = (metric) => {
3105
3141
  if (controlledSizeMetric === void 0) setInternalSizeMetric(metric);
3106
3142
  onSizeMetricChange?.(metric);
@@ -3132,7 +3168,7 @@ function GenreTreeView({
3132
3168
  allowWheelRotation: internalAllowWheelRotation,
3133
3169
  toggleWheelRotation,
3134
3170
  onNodeHover: handleNodeHover
3135
- } = (0, import_genre_tree31.useGenreTreeViewState)({
3171
+ } = (0, import_genre_tree32.useGenreTreeViewState)({
3136
3172
  scope,
3137
3173
  getBackendBaseUrl,
3138
3174
  viewMode: controlledViewMode,
@@ -3142,7 +3178,7 @@ function GenreTreeView({
3142
3178
  artistUuid
3143
3179
  });
3144
3180
  const restoreRevision = viewportRestore?.revision;
3145
- const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react19.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
3181
+ const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react20.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
3146
3182
  let restoreRootUuid = stackedRestoreOwner.rootUuid;
3147
3183
  if (stackedRestoreOwner.revision !== restoreRevision) {
3148
3184
  restoreRootUuid = selectedGenrePlaylist?.root.uuid;
@@ -3151,14 +3187,14 @@ function GenreTreeView({
3151
3187
  restoreRootUuid = selectedGenrePlaylist.root.uuid;
3152
3188
  setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });
3153
3189
  }
3154
- const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree31.genreUpdateMutationKey }) > 0;
3155
- const { mutate: updateGenre } = (0, import_genre_tree31.useUpdateGenre)(scope, getBackendBaseUrl);
3190
+ const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree32.genreUpdateMutationKey }) > 0;
3191
+ const { mutate: updateGenre } = (0, import_genre_tree32.useUpdateGenre)(scope, getBackendBaseUrl);
3156
3192
  const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;
3157
3193
  const isArtistFiltered = artistUuid !== null;
3158
3194
  const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
3159
- const artistResult = (0, import_genre_tree31.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
3195
+ const artistResult = (0, import_genre_tree32.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
3160
3196
  const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
3161
- const filterArtist = (0, import_react19.useMemo)(
3197
+ const filterArtist = (0, import_react20.useMemo)(
3162
3198
  () => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
3163
3199
  [artistUuid, filterArtistName]
3164
3200
  );
@@ -3173,14 +3209,14 @@ function GenreTreeView({
3173
3209
  if (selectedGenreUuid !== null) clearSelection();
3174
3210
  changeSong(uuid);
3175
3211
  };
3176
- const openSongRef = (0, import_react19.useRef)(openSong);
3212
+ const openSongRef = (0, import_react20.useRef)(openSong);
3177
3213
  openSongRef.current = openSong;
3178
- const resolvedRenderSongLink = (0, import_react19.useCallback)(
3214
+ const resolvedRenderSongLink = (0, import_react20.useCallback)(
3179
3215
  (song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
3180
3216
  [renderSongLink]
3181
3217
  );
3182
- const [expandedSongUuid, setExpandedSongUuid] = (0, import_react19.useState)(null);
3183
- const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react19.useState)(null);
3218
+ const [expandedSongUuid, setExpandedSongUuid] = (0, import_react20.useState)(null);
3219
+ const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react20.useState)(null);
3184
3220
  const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
3185
3221
  const songBaseUrl = getBackendBaseUrl;
3186
3222
  const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
@@ -3227,8 +3263,8 @@ function GenreTreeView({
3227
3263
  }
3228
3264
  });
3229
3265
  const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
3230
- const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react19.useState)(false);
3231
- const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react19.useState)(false);
3266
+ const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react20.useState)(false);
3267
+ const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react20.useState)(false);
3232
3268
  const isCollapsed = collapsed ?? uncontrolledCollapsed;
3233
3269
  const isExpanded = expanded ?? uncontrolledExpanded;
3234
3270
  const changeCollapsed = (next) => {
@@ -3239,30 +3275,30 @@ function GenreTreeView({
3239
3275
  setUncontrolledExpanded(next);
3240
3276
  onExpandedChange?.(next);
3241
3277
  };
3242
- (0, import_react19.useEffect)(() => {
3278
+ (0, import_react20.useEffect)(() => {
3243
3279
  setUncontrolledCollapsed(false);
3244
3280
  }, [selectedGenreUuid, artistUuid, songUuid]);
3245
- const [isWheelRevealed, setIsWheelRevealed] = (0, import_react19.useState)(false);
3281
+ const [isWheelRevealed, setIsWheelRevealed] = (0, import_react20.useState)(false);
3246
3282
  const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
3247
3283
  const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);
3248
- const [resolveStyle, setResolveStyle] = (0, import_react19.useState)(null);
3249
- const handleNodeStyleResolverChange = (0, import_react19.useCallback)(
3284
+ const [resolveStyle, setResolveStyle] = (0, import_react20.useState)(null);
3285
+ const handleNodeStyleResolverChange = (0, import_react20.useCallback)(
3250
3286
  (resolver) => setResolveStyle(() => resolver),
3251
3287
  []
3252
3288
  );
3253
- const panelRef = (0, import_react19.useRef)(null);
3254
- const obscuredInset = (0, import_ui25.useObscuredInset)(panelRef);
3289
+ const panelRef = (0, import_react20.useRef)(null);
3290
+ const obscuredInset = (0, import_ui26.useObscuredInset)(panelRef);
3255
3291
  const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
3256
3292
  const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
3257
- const treeNodes = (0, import_react19.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
3293
+ const treeNodes = (0, import_react20.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
3258
3294
  const relations = (0, import_genre_tree_view5.useGenreNodeRelations)(
3259
3295
  treeNodes,
3260
3296
  !overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
3261
3297
  resolveStyle
3262
3298
  );
3263
- const treeStyles = (0, import_react19.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
3264
- const validSelectedGenreUuid = (0, import_genre_tree30.toGenreUuid)(selectedGenreUuid);
3265
- const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: validSelectedGenreUuid, previous: null });
3299
+ const treeStyles = (0, import_react20.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
3300
+ const validSelectedGenreUuid = (0, import_genre_tree31.toGenreUuid)(selectedGenreUuid);
3301
+ const [selectionHistory, setSelectionHistory] = (0, import_react20.useState)({ current: validSelectedGenreUuid, previous: null });
3266
3302
  if (selectionHistory.current !== validSelectedGenreUuid) {
3267
3303
  setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
3268
3304
  }
@@ -3288,7 +3324,7 @@ function GenreTreeView({
3288
3324
  const handleGenreSearchZoomIn = () => {
3289
3325
  if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, "zoom-in");
3290
3326
  };
3291
- const zoomInRef = (0, import_react19.useRef)(void 0);
3327
+ const zoomInRef = (0, import_react20.useRef)(void 0);
3292
3328
  zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : void 0;
3293
3329
  const genrePlaylist = selectedGenrePlaylist;
3294
3330
  const criteria = genrePlaylist?.criteria;
@@ -3356,6 +3392,7 @@ function GenreTreeView({
3356
3392
  activePanel = {
3357
3393
  title: otherPanel.title,
3358
3394
  content: otherPanel.content,
3395
+ cover: otherPanel.cover,
3359
3396
  aside: otherPanel.extraContent,
3360
3397
  expanded: otherPanel.expanded ?? false,
3361
3398
  onExpandedChange: otherPanel.onExpandedChange,
@@ -3380,7 +3417,7 @@ function GenreTreeView({
3380
3417
  center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
3381
3418
  } : void 0;
3382
3419
  const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3383
- import_ui25.IconButton,
3420
+ import_ui26.IconButton,
3384
3421
  {
3385
3422
  "aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
3386
3423
  style: activePanel.headerAccent && { color: "inherit" },
@@ -3446,13 +3483,16 @@ function GenreTreeView({
3446
3483
  onPrevious: handlePrevious,
3447
3484
  onQueryChange: onSearchQueryChange,
3448
3485
  onFocus: onSearchFocus,
3486
+ trailingAction: searchTrailingAction,
3487
+ trailingActionBreakpoint: "md",
3488
+ fullWidthBreakpoint: searchFullWidthBreakpoint,
3449
3489
  extraGroups: extraSearchGroups
3450
3490
  }
3451
3491
  ),
3452
3492
  !isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
3453
3493
  /* @__PURE__ */ (0, import_jsx_runtime52.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: [
3454
3494
  !isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3455
- import_ui25.SegmentedControl,
3495
+ import_ui26.SegmentedControl,
3456
3496
  {
3457
3497
  "aria-label": "Tree view mode",
3458
3498
  value: viewMode,
@@ -3472,7 +3512,7 @@ function GenreTreeView({
3472
3512
  role: "group",
3473
3513
  "aria-label": "Tree display options",
3474
3514
  children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3475
- import_ui25.Button,
3515
+ import_ui26.Button,
3476
3516
  {
3477
3517
  variant: allowWheelRotation ? "default" : "outline",
3478
3518
  size: "sm",
@@ -3483,7 +3523,7 @@ function GenreTreeView({
3483
3523
  }
3484
3524
  ),
3485
3525
  !isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3486
- import_ui25.IconTextButton,
3526
+ import_ui26.IconTextButton,
3487
3527
  {
3488
3528
  icon: import_lucide_react17.Plus,
3489
3529
  text: "Add root",
@@ -3496,12 +3536,21 @@ function GenreTreeView({
3496
3536
  "div",
3497
3537
  {
3498
3538
  "data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
3499
- className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
3539
+ className: [
3540
+ "genre-tree-view relative flex flex-col h-full",
3541
+ placement === "regions" && REGIONS_CLASS,
3542
+ 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))]",
3543
+ className2
3544
+ ].filter(Boolean).join(" "),
3500
3545
  children: [
3501
3546
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3502
3547
  "div",
3503
3548
  {
3504
- 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"}`,
3549
+ className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? [
3550
+ "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",
3551
+ searchFullWidthBreakpoint === "sm" ? "max-sm:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))]" : "max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))]",
3552
+ searchTrailingAction ? "max-md:top-[max(var(--layout-panel-inset),env(safe-area-inset-top))]" : "max-md:top-[var(--layout-band-top)]"
3553
+ ].join(" ") : "left-5 top-5"}`,
3505
3554
  children: actions
3506
3555
  }
3507
3556
  ),
@@ -3631,11 +3680,16 @@ function GenreTreeView({
3631
3680
  }
3632
3681
  ) }),
3633
3682
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3634
- import_ui25.DetailPanel,
3683
+ GenreOverviewDetailPanel,
3635
3684
  {
3685
+ genreUuid: !otherPanel && genreContent.name && selectedGenreUuid ? (0, import_genre_tree31.toGenreUuid)(selectedGenreUuid) : null,
3686
+ scope,
3687
+ getBackendBaseUrl,
3688
+ criteriaOverviewSchema,
3636
3689
  ref: panelRef,
3637
3690
  side: "left",
3638
3691
  title: activePanel?.title ?? "",
3692
+ cover: activePanel?.cover,
3639
3693
  titleInSearch: !isLoading && !isError,
3640
3694
  headerAccent: activePanel?.headerAccent,
3641
3695
  headerActions: expandButton,
@@ -3661,13 +3715,13 @@ function GenreTreeView({
3661
3715
  var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
3662
3716
 
3663
3717
  // src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
3664
- var import_react20 = require("react");
3718
+ var import_react21 = require("react");
3665
3719
  var import_lucide_react19 = require("lucide-react");
3666
- var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
3667
3720
  var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
3721
+ var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
3668
3722
  var import_track_noun4 = require("@behindthemusictree/app-kit/track-noun");
3669
3723
  var import_jsx_runtime53 = require("react/jsx-runtime");
3670
- var useBrowserLayoutEffect = typeof window === "undefined" ? import_react20.useEffect : import_react20.useLayoutEffect;
3724
+ var useBrowserLayoutEffect = typeof window === "undefined" ? import_react21.useEffect : import_react21.useLayoutEffect;
3671
3725
  function TrackListSidebar({
3672
3726
  className: className2 = "",
3673
3727
  renderDuration,
@@ -3679,18 +3733,18 @@ function TrackListSidebar({
3679
3733
  renderArtistLink,
3680
3734
  renderSongLink
3681
3735
  }) {
3682
- const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree32.useTrackList)();
3736
+ const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree33.useTrackList)();
3683
3737
  const trackNoun = (0, import_track_noun4.useTrackNoun)();
3684
- const trackListRef = (0, import_react20.useRef)(null);
3685
- const previousOriginRef = (0, import_react20.useRef)(trackList?.origin ?? null);
3686
- const handledAutoAdvanceRequestIdRef = (0, import_react20.useRef)(null);
3687
- const shouldFollowPlaybackRef = (0, import_react20.useRef)(true);
3688
- const programmaticScrollTopRef = (0, import_react20.useRef)(null);
3689
- const userScrollIntentRef = (0, import_react20.useRef)(false);
3690
- const userScrollIntentTimerRef = (0, import_react20.useRef)(null);
3691
- const loadMoreSentinelRef = (0, import_react20.useRef)(null);
3738
+ const trackListRef = (0, import_react21.useRef)(null);
3739
+ const previousOriginRef = (0, import_react21.useRef)(trackList?.origin ?? null);
3740
+ const handledAutoAdvanceRequestIdRef = (0, import_react21.useRef)(null);
3741
+ const shouldFollowPlaybackRef = (0, import_react21.useRef)(true);
3742
+ const programmaticScrollTopRef = (0, import_react21.useRef)(null);
3743
+ const userScrollIntentRef = (0, import_react21.useRef)(false);
3744
+ const userScrollIntentTimerRef = (0, import_react21.useRef)(null);
3745
+ const loadMoreSentinelRef = (0, import_react21.useRef)(null);
3692
3746
  const hasMore = !!trackList && trackList.nextPage !== null;
3693
- (0, import_react20.useEffect)(() => {
3747
+ (0, import_react21.useEffect)(() => {
3694
3748
  const sentinel = loadMoreSentinelRef.current;
3695
3749
  if (!hasMore || !sentinel) return;
3696
3750
  const observer = new IntersectionObserver((entries) => {
@@ -3710,11 +3764,11 @@ function TrackListSidebar({
3710
3764
  programmaticScrollTopRef.current = null;
3711
3765
  if (trackListRef.current) trackListRef.current.scrollTop = 0;
3712
3766
  }, [trackList?.origin]);
3713
- (0, import_react20.useEffect)(() => {
3767
+ (0, import_react21.useEffect)(() => {
3714
3768
  const list = trackListRef.current;
3715
3769
  if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;
3716
3770
  }, [isCollapsed]);
3717
- (0, import_react20.useEffect)(
3771
+ (0, import_react21.useEffect)(
3718
3772
  () => () => {
3719
3773
  if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);
3720
3774
  },
@@ -3782,7 +3836,7 @@ function TrackListSidebar({
3782
3836
  /* @__PURE__ */ (0, import_jsx_runtime53.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_runtime53.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
3783
3837
  ] }),
3784
3838
  /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
3785
- 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 `,
3839
+ 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 `,
3786
3840
  `${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
3787
3841
  ] })
3788
3842
  ] }),
@@ -3830,16 +3884,16 @@ function TrackListSidebar({
3830
3884
  }
3831
3885
 
3832
3886
  // src/genre-tree/PlayerPanel.tsx
3833
- var import_react21 = require("react");
3887
+ var import_react22 = require("react");
3834
3888
  var import_lucide_react21 = require("lucide-react");
3835
3889
  var import_tailwind_merge = require("tailwind-merge");
3836
3890
  var import_player14 = require("@behindthemusictree/app-kit/player");
3837
- var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
3838
- var import_ui26 = require("@behindthemusictree/ui");
3891
+ var import_genre_tree36 = require("@behindthemusictree/app-kit/genre-tree");
3892
+ var import_ui27 = require("@behindthemusictree/ui");
3839
3893
 
3840
3894
  // src/genre-tree/PlayerControls.tsx
3841
3895
  var import_lucide_react20 = require("lucide-react");
3842
- var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
3896
+ var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
3843
3897
  var import_player13 = require("@behindthemusictree/app-kit/player");
3844
3898
  var import_jsx_runtime54 = require("react/jsx-runtime");
3845
3899
  function PlayerControls() {
@@ -3853,7 +3907,7 @@ function PlayerControls() {
3853
3907
  setVolume,
3854
3908
  volume
3855
3909
  } = (0, import_player13.usePlayer)();
3856
- const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree34.useTrackList)();
3910
+ const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree35.useTrackList)();
3857
3911
  const currentTime = (0, import_player13.useCurrentTime)();
3858
3912
  const isBusy = isLoading || playState === import_player13.PlayStates.LOADING;
3859
3913
  const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;
@@ -3867,7 +3921,7 @@ function PlayerControls() {
3867
3921
  className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
3868
3922
  children: [
3869
3923
  /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
3870
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree34.formatTime)(safeCurrentTime) }),
3924
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree35.formatTime)(safeCurrentTime) }),
3871
3925
  /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3872
3926
  "input",
3873
3927
  {
@@ -3882,7 +3936,7 @@ function PlayerControls() {
3882
3936
  onChange: (event) => seekTo(Number(event.currentTarget.value))
3883
3937
  }
3884
3938
  ),
3885
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree34.formatTime)(safeDuration) })
3939
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree35.formatTime)(safeDuration) })
3886
3940
  ] }),
3887
3941
  /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
3888
3942
  /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
@@ -3961,13 +4015,13 @@ function PlayerPanel({
3961
4015
  renderSongLink
3962
4016
  }) {
3963
4017
  const { playerTrackObject, retryPlayback, stop } = (0, import_player14.usePlayer)();
3964
- const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree35.useTrackListSidebarVisibility)();
3965
- const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react21.useState)("");
4018
+ const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree36.useTrackListSidebarVisibility)();
4019
+ const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react22.useState)("");
3966
4020
  const loadedTrackTitle = playerTrackObject?.track.title;
3967
- (0, import_react21.useEffect)(() => {
4021
+ (0, import_react22.useEffect)(() => {
3968
4022
  if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
3969
4023
  }, [loadedTrackTitle]);
3970
- const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react21.useState)(false);
4024
+ const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react22.useState)(false);
3971
4025
  const isExtendRequested = expanded ?? uncontrolledExtended;
3972
4026
  const setIsExtendRequested = (next) => {
3973
4027
  setUncontrolledExtended(next);
@@ -4002,7 +4056,7 @@ function PlayerPanel({
4002
4056
  style: isExtended ? { width: extendedWidth } : void 0,
4003
4057
  children: [
4004
4058
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
4005
- import_ui26.PanelEdgeTab,
4059
+ import_ui27.PanelEdgeTab,
4006
4060
  {
4007
4061
  side: "right",
4008
4062
  edge: tabEdge,
@@ -4022,7 +4076,7 @@ function PlayerPanel({
4022
4076
  /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
4023
4077
  /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: [
4024
4078
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }),
4025
- playerTrackObject && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_ui26.IconButton, { "aria-label": "Close player", onClick: stop, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react21.X, { "aria-hidden": "true", className: "h-4 w-4" }) })
4079
+ playerTrackObject && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_ui27.IconButton, { "aria-label": "Close player", onClick: stop, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react21.X, { "aria-hidden": "true", className: "h-4 w-4" }) })
4026
4080
  ] }),
4027
4081
  /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "relative w-full shrink-0", children: [
4028
4082
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_player14.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
@@ -4061,7 +4115,7 @@ function PlayerPanel({
4061
4115
  // src/genre-tree/Rating.tsx
4062
4116
  var import_uuid = require("uuid");
4063
4117
  var import_ai = require("react-icons/ai");
4064
- var import_genre_tree36 = require("@behindthemusictree/app-kit/genre-tree");
4118
+ var import_genre_tree37 = require("@behindthemusictree/app-kit/genre-tree");
4065
4119
  var import_jsx_runtime56 = require("react/jsx-runtime");
4066
4120
  function Rating({ rating, handleChange }) {
4067
4121
  const instanceId = (0, import_uuid.v4)();
@@ -4073,7 +4127,7 @@ function Rating({ rating, handleChange }) {
4073
4127
  className: "w-6 h-6 opacity-0",
4074
4128
  type: "radio",
4075
4129
  name: "rating",
4076
- value: i === 0 ? import_genre_tree36.FORM_RATING_NULL_VALUE : i,
4130
+ value: i === 0 ? import_genre_tree37.FORM_RATING_NULL_VALUE : i,
4077
4131
  checked: rating === (i === 0 ? null : i),
4078
4132
  onChange: handleChange
4079
4133
  }
@@ -4082,7 +4136,7 @@ function Rating({ rating, handleChange }) {
4082
4136
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
4083
4137
  import_ai.AiOutlineStar,
4084
4138
  {
4085
- 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)]"}`
4139
+ 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)]"}`
4086
4140
  }
4087
4141
  ),
4088
4142
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "flex-grow w-8" }),
@@ -4097,8 +4151,8 @@ function Rating({ rating, handleChange }) {
4097
4151
  }
4098
4152
 
4099
4153
  // src/genre-tree/EntityDetailPanel.tsx
4100
- var import_react22 = require("react");
4101
- var import_ui27 = require("@behindthemusictree/ui");
4154
+ var import_react23 = require("react");
4155
+ var import_ui28 = require("@behindthemusictree/ui");
4102
4156
  var import_jsx_runtime57 = require("react/jsx-runtime");
4103
4157
  function EntityDetailPanel({
4104
4158
  scope,
@@ -4116,8 +4170,8 @@ function EntityDetailPanel({
4116
4170
  edgeTab,
4117
4171
  ...navigation
4118
4172
  }) {
4119
- const [expandedSongUuid, setExpandedSongUuid] = (0, import_react22.useState)(null);
4120
- const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react22.useState)(null);
4173
+ const [expandedSongUuid, setExpandedSongUuid] = (0, import_react23.useState)(null);
4174
+ const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react23.useState)(null);
4121
4175
  const panel = useEntityPanel({
4122
4176
  scope,
4123
4177
  getBackendBaseUrl,
@@ -4142,10 +4196,11 @@ function EntityDetailPanel({
4142
4196
  });
4143
4197
  if (!panel) return null;
4144
4198
  return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
4145
- import_ui27.DetailPanel,
4199
+ import_ui28.DetailPanel,
4146
4200
  {
4147
4201
  side: "left",
4148
4202
  title: panel.title,
4203
+ cover: panel.cover,
4149
4204
  titleInSearch: true,
4150
4205
  onClose: panel.onClose,
4151
4206
  collapsed,