bearminion 1.3.0 → 1.4.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/ui/mount.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { a as sectionFieldKey, i as isPropShown, t as defaultTheme } from "../theme-DMpt3hcT.js";
2
2
  import { A as isImagePosition, D as IMAGE_FITS, E as DEFAULT_IMAGE_POSITION, O as IMAGE_POSITIONS, T as DEFAULT_IMAGE_FIT, i as isSystemPage, j as withImageLayout, k as isImageFit } from "../page-ON4Jkcm-.js";
3
3
  import { applyTextMark, fontMarks, marksFromEmphasis, reconcileMarks, renderMarkedHtml } from "../marks.js";
4
- import { c as hasThemeColors, d as tokenToHex, f as formatJsonLd, i as contrastChecks, m as parseJsonLdInput, n as HEX_COLOR, o as derivePalette, p as jsonLdWarnings, r as OVERRIDE_TOKENS, s as hasOverrides, t as DEFAULT_BRAND, u as themeCss } from "../theme-colors-B2kAO2n6.js";
4
+ import { _ as consentCopy, b as jsonLdWarnings, c as hasThemeColors, d as tokenToHex, f as CONSENT_COPY, h as CONSENT_LIMITS, i as contrastChecks, n as HEX_COLOR, o as derivePalette, r as OVERRIDE_TOKENS, s as hasOverrides, t as DEFAULT_BRAND, u as themeCss, v as consentTextIssues, x as parseJsonLdInput, y as formatJsonLd } from "../theme-colors-zICpze42.js";
5
5
  import { _ as writeSaveNotice, a as localDraftStorage, d as removeDraft, f as savedNoticeFor, g as writeDraftRecord, h as sweepExpiredDrafts, i as isForeignSave, l as readDraftRecord, m as siteSavedKey, n as draftBannerText, o as pageDraftKey, p as siteDraftKey, r as hashText, s as pageSavedKey, t as assessStoredDraft, u as reloadDecision, x as draftImageUsages } from "../draft-store-1Y4-sn45.js";
6
6
  import { isSafeHref, markdownFromHtml, renderRichText, richLinkAt, sanitizeRichHtml, stripPlainRich, updateRichLink } from "../rich-text.js";
7
7
  import { Component, Fragment, createContext, isValidElement, options, render } from "preact";
@@ -13832,6 +13832,41 @@ function imageSrcAt(doc, path) {
13832
13832
  if (typeof value === "string") return value;
13833
13833
  return isRecord$2(value) && typeof value.src === "string" ? value.src : "";
13834
13834
  }
13835
+ const CONSENT_KEYS = [
13836
+ "title",
13837
+ "body",
13838
+ "accept",
13839
+ "reject",
13840
+ "settings",
13841
+ "policyLabel",
13842
+ "policyHref"
13843
+ ];
13844
+ /** The banner texts stored in a site draft. Anything else in `consent`, such as `enabled`, is left out. */
13845
+ function consentTextOf(site) {
13846
+ const stored = getAt(site, "consent");
13847
+ const text = {};
13848
+ if (!isRecord$2(stored)) return text;
13849
+ for (const key of CONSENT_KEYS) {
13850
+ const value = stored[key];
13851
+ if (typeof value === "string") text[key] = value;
13852
+ }
13853
+ return text;
13854
+ }
13855
+ /** Whether the draft asks visitors before analytics runs. Only an explicit `false` turns it off. */
13856
+ function consentEnabled(site) {
13857
+ return getAt(site, "consent.enabled") !== false;
13858
+ }
13859
+ /** Whether the draft holds an analytics snippet that the banner would guard. */
13860
+ function hasAnalyticsSnippet(site) {
13861
+ return ["analytics.head", "analytics.bodyEnd"].some((path) => {
13862
+ const value = getAt(site, path);
13863
+ return typeof value === "string" && value.trim() !== "";
13864
+ });
13865
+ }
13866
+ /** Where the draft reopens the banner. Anything but `icon` is the footer link. */
13867
+ function consentReopenOf(site) {
13868
+ return getAt(site, "consent.reopen") === "icon" ? "icon" : "footer";
13869
+ }
13835
13870
  //#endregion
13836
13871
  //#region src/ui/controllers/reactions.ts
13837
13872
  /** Signal effects that keep the page, storage and history in step with the editor state. */
@@ -16365,31 +16400,25 @@ function CommitDialog({ info, unsaved, onDone, onClose }) {
16365
16400
  });
16366
16401
  }
16367
16402
  //#endregion
16368
- //#region src/ui/forms/segmented.tsx
16369
- /** Segmented control for a short list of exclusive choices. */
16370
- function Segmented({ label, value, options, onChange, hideLabel }) {
16371
- const values = options.map((option) => option.value);
16372
- return /* @__PURE__ */ jsxs("div", {
16373
- class: "bm-field",
16374
- children: [!hideLabel && /* @__PURE__ */ jsx("span", {
16375
- class: "bm-label",
16376
- children: label
16377
- }), /* @__PURE__ */ jsx("div", {
16378
- class: "bm-segmented",
16379
- role: "radiogroup",
16380
- "aria-label": label,
16381
- onKeyDown: (event) => stepRadio(event, values, value, onChange),
16382
- children: options.map((option) => /* @__PURE__ */ jsx("button", {
16383
- type: "button",
16384
- role: "radio",
16385
- "aria-checked": value === option.value,
16386
- tabIndex: value === option.value ? 0 : -1,
16387
- onClick: () => onChange(option.value),
16388
- children: option.label
16389
- }, option.value))
16390
- })]
16391
- });
16392
- }
16403
+ //#region src/ui/context.ts
16404
+ const LinksContext = createContext({
16405
+ pages: [],
16406
+ currentSlug: "index",
16407
+ anchors: [],
16408
+ editLink: () => {}
16409
+ });
16410
+ const IssueContext = createContext([]);
16411
+ /** Which props of the section being edited can be dropped. ValueEditor reads it to offer Remove, Add and "empty hides it". */
16412
+ const OptionalContext = createContext({ content: void 0 });
16413
+ /**
16414
+ * What the schema of the section being edited says about its fields, by field key: fixed choices and their icons
16415
+ * (ValueEditor shows a picker) and image fields (MissingField shows an image slot).
16416
+ */
16417
+ const FieldsContext = createContext({
16418
+ choices: void 0,
16419
+ icons: void 0,
16420
+ images: void 0
16421
+ });
16393
16422
  //#endregion
16394
16423
  //#region src/ui/info.tsx
16395
16424
  const GAP = 6;
@@ -16487,438 +16516,118 @@ function Info({ text, label = "More info", id }) {
16487
16516
  });
16488
16517
  }
16489
16518
  //#endregion
16490
- //#region src/ui/dialogs/history-dialog.tsx
16491
- function formatVersionTime(iso) {
16492
- const date = new Date(iso);
16493
- if (Number.isNaN(date.getTime())) return iso;
16494
- return date.toLocaleString(void 0, {
16495
- month: "short",
16496
- day: "numeric",
16497
- hour: "2-digit",
16498
- minute: "2-digit"
16499
- });
16500
- }
16501
- const VERSION_CAP = 50;
16502
- function startOfDay(date) {
16503
- return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
16519
+ //#region src/ui/image-field.tsx
16520
+ const FIT_LABEL = {
16521
+ cover: "Cover",
16522
+ contain: "Contain",
16523
+ auto: "Auto"
16524
+ };
16525
+ const FIT_HINT = {
16526
+ cover: "Fills the frame and crops the overflow.",
16527
+ contain: "Shows the whole image inside the frame.",
16528
+ auto: "Keeps the image’s own size and aspect ratio."
16529
+ };
16530
+ const POSITION_LABEL = {
16531
+ "top left": "Top left",
16532
+ top: "Top",
16533
+ "top right": "Top right",
16534
+ left: "Left",
16535
+ center: "Center",
16536
+ right: "Right",
16537
+ "bottom left": "Bottom left",
16538
+ bottom: "Bottom",
16539
+ "bottom right": "Bottom right"
16540
+ };
16541
+ /** Drop the keys that equal their default so saved JSON only holds real choices. */
16542
+ function compact(next) {
16543
+ const { fit, position, hidden, ...rest } = next;
16544
+ return {
16545
+ ...rest,
16546
+ ...hidden === true ? { hidden } : {},
16547
+ ...fit && fit !== "cover" ? { fit } : {},
16548
+ ...position && position !== "center" ? { position } : {}
16549
+ };
16504
16550
  }
16505
- /** Today / Yesterday / "12 Mar" (with the year when it is not this one). */
16506
- function versionDay(iso, now = /* @__PURE__ */ new Date()) {
16507
- const date = new Date(iso);
16508
- if (Number.isNaN(date.getTime())) return iso;
16509
- const days = Math.round((startOfDay(now) - startOfDay(date)) / 864e5);
16510
- if (days === 0) return "Today";
16511
- if (days === 1) return "Yesterday";
16512
- return date.toLocaleDateString(void 0, {
16513
- day: "numeric",
16514
- month: "short",
16515
- ...date.getFullYear() === now.getFullYear() ? {} : { year: "numeric" }
16516
- });
16551
+ /**
16552
+ * True when `src` is a local image whose file is gone. The dev route answers HEAD with 404 for those; remote URLs and
16553
+ * placeholders are never "missing". Rechecks whenever the path changes.
16554
+ */
16555
+ function useMissingFile(src) {
16556
+ const [missing, setMissing] = useState(false);
16557
+ useEffect(() => {
16558
+ const url = previewSrc(src);
16559
+ if (!url.startsWith("/__bearminion/assets?")) {
16560
+ setMissing(false);
16561
+ return;
16562
+ }
16563
+ let current = true;
16564
+ fetch(url, {
16565
+ method: "HEAD",
16566
+ cache: "no-store"
16567
+ }).then((response) => {
16568
+ if (current) setMissing(response.status === 404);
16569
+ }).catch(() => {
16570
+ if (current) setMissing(false);
16571
+ });
16572
+ return () => {
16573
+ current = false;
16574
+ };
16575
+ }, [src]);
16576
+ return missing;
16517
16577
  }
16518
- function versionClock(iso) {
16519
- const date = new Date(iso);
16520
- return Number.isNaN(date.getTime()) ? "" : date.toLocaleTimeString(void 0, {
16521
- hour: "2-digit",
16522
- minute: "2-digit",
16523
- hour12: false
16524
- });
16578
+ function previewSrc(src) {
16579
+ if (src === "" || src === "placeholder") return "";
16580
+ if (/^https?:\/\//i.test(src) || src.startsWith("/")) return src;
16581
+ return `/__bearminion/assets?src=${encodeURIComponent(src.replace(/^\//, ""))}`;
16525
16582
  }
16526
- /** "just now", "2 min ago", "3 h ago"; older than a day shows only the clock time. */
16527
- function versionAgo(iso, now = Date.now()) {
16528
- const then = new Date(iso).getTime();
16529
- if (Number.isNaN(then)) return "";
16530
- const minutes = Math.max(0, Math.round((now - then) / 6e4));
16531
- if (minutes < 1) return "just now";
16532
- if (minutes < 60) return `${minutes} min ago`;
16533
- const hours = Math.round(minutes / 60);
16534
- return hours < 24 ? `${hours} h ago` : versionClock(iso);
16583
+ /** Only react to files. Dragging text or a link over a drop target is not an upload. */
16584
+ function hasFiles(event) {
16585
+ return Array.from(event.dataTransfer?.types ?? []).includes("Files");
16535
16586
  }
16536
- /** "title, hero › heading +2": the first changed fields of one save, for the collapsed row. */
16537
- function versionSummary(list) {
16538
- if (!list || list.length === 0) return "";
16539
- const names = [...new Set(list.map((item) => item.field))];
16540
- return names.length <= 3 ? names.join(", ") : `${names.slice(0, 3).join(", ")} +${names.length - 3}`;
16587
+ function fileName(src) {
16588
+ return src.split("/").pop() || src;
16541
16589
  }
16590
+ /** The tab last used in this page session, so a second pick starts where the first ended. */
16591
+ let lastTab = null;
16592
+ const ACCEPT = "image/png,image/jpeg,image/webp,image/gif,image/avif";
16593
+ const FOCUSABLE = "button:not(:disabled), input:not(:disabled), [tabindex=\"0\"]";
16542
16594
  /**
16543
- * Saved versions of this page and of the site, newest first and grouped by day. A version shows what that save changed,
16544
- * and Restore loads it into the draft. Nothing is written until the next save, and the restore can be undone from here.
16595
+ * One control for every image in the editor. Empty: a slot that opens the picker.
16596
+ * Filled: thumbnail, file name, alt text, Change and Remove. The picker is a modal
16597
+ * with an Upload tab (drop or browse) and a Library tab (pick or delete).
16545
16598
  */
16546
- function HistoryDialog({ slug, labels, page, onRestore, onUndo, onClose }) {
16599
+ function ImageField({ label, path, value, images, withAlt = true, layout = true, hideable = false, onChange, onUploaded, onDeleted }) {
16600
+ const [open, setOpen] = useState(false);
16601
+ const [error, setError] = useState("");
16602
+ const [over, setOver] = useState(false);
16547
16603
  const root = useRef(null);
16548
- useDialogFocus(root);
16549
- const [scope, setScope] = useState("page");
16550
- const [entries, setEntries] = useState(null);
16551
- const [diffs, setDiffs] = useState({});
16552
- const [failed, setFailed] = useState(false);
16553
- const [openId, setOpenId] = useState(null);
16554
- const [restored, setRestored] = useState(null);
16555
- const base = `${scope}:${slug}`;
16556
- useEffect(() => {
16557
- let live = true;
16558
- setEntries(null);
16559
- setDiffs({});
16560
- setOpenId(null);
16561
- setRestored(null);
16562
- setFailed(false);
16563
- const load = async () => {
16564
- const listed = await listHistory(scope, slug);
16565
- if (!listed.ok) throw new Error(listed.message);
16566
- const body = listed.value;
16567
- if (!live) return;
16568
- setEntries(body.entries);
16569
- const data = await Promise.all(body.entries.map(async (entry) => {
16570
- const version = await getHistoryVersion(scope, slug, entry.id);
16571
- return version.ok ? version.value : null;
16572
- }));
16573
- if (!live) return;
16574
- const next = {};
16575
- body.entries.forEach((entry, index) => {
16576
- const after = data[index];
16577
- const before = data[index + 1];
16578
- if (after === null || before === null || before === void 0) return;
16579
- next[entry.id] = scope === "page" ? describePageChanges(before, after, labels) : describeSiteChanges(before, after);
16580
- });
16581
- setDiffs(next);
16582
- };
16583
- load().catch(() => live && setFailed(true));
16584
- return () => {
16585
- live = false;
16586
- };
16587
- }, [base]);
16588
- async function restore(entry) {
16589
- const version = await getHistoryVersion(scope, slug, entry.id);
16590
- if (!version.ok) {
16591
- setFailed(true);
16592
- return;
16593
- }
16594
- const when = formatVersionTime(entry.at);
16595
- onRestore(scope, version.value, when);
16596
- setRestored(when);
16597
- }
16598
- const days = [];
16599
- entries?.forEach((entry, index) => {
16600
- const day = versionDay(entry.at);
16601
- const last = days[days.length - 1];
16602
- if (last && last.day === day) last.items.push({
16603
- entry,
16604
- index
16605
- });
16606
- else days.push({
16607
- day,
16608
- items: [{
16609
- entry,
16610
- index
16611
- }]
16612
- });
16613
- });
16614
- return /* @__PURE__ */ jsxs("div", {
16615
- class: "bm-dialog bm-changes",
16616
- role: "dialog",
16617
- "aria-modal": "true",
16618
- "aria-label": "Version history",
16619
- ref: root,
16620
- style: "top:12%;left:50%;transform:translateX(-50%);",
16621
- children: [
16622
- /* @__PURE__ */ jsxs("div", {
16623
- class: "bm-dialog-head",
16624
- children: [/* @__PURE__ */ jsxs("div", {
16625
- class: "bm-dialog-heading",
16626
- children: [/* @__PURE__ */ jsxs("h2", {
16627
- class: "bm-dialog-title",
16628
- children: ["Version history", /* @__PURE__ */ jsx(Info, {
16629
- label: "Where versions are kept",
16630
- text: /* @__PURE__ */ jsxs(Fragment$1, { children: [
16631
- "Versions are kept only on this computer, in ",
16632
- /* @__PURE__ */ jsx("code", { children: ".editor/history" }),
16633
- ". They are not in git and not on the published site. The newest ",
16634
- VERSION_CAP,
16635
- " stay. To clear them, stop the dev server and delete the ",
16636
- /* @__PURE__ */ jsx("code", { children: ".editor" }),
16637
- " folder in your project root."
16638
- ] })
16639
- })]
16640
- }), /* @__PURE__ */ jsx("p", {
16641
- class: "bm-dialog-sub",
16642
- children: "Every save is kept. Restore loads a version into the draft; nothing is written until you save."
16643
- })]
16644
- }), /* @__PURE__ */ jsx(DialogClose, { onClose })]
16645
- }),
16646
- /* @__PURE__ */ jsx(Segmented, {
16647
- hideLabel: true,
16648
- label: "Scope",
16649
- value: scope,
16650
- options: [{
16651
- value: "page",
16652
- label: `Page "${page.title}"`
16653
- }, {
16654
- value: "site",
16655
- label: "Site"
16656
- }],
16657
- onChange: (value) => setScope(value === "site" ? "site" : "page")
16658
- }),
16659
- restored !== null && /* @__PURE__ */ jsxs("div", {
16660
- class: "bm-restored",
16661
- role: "status",
16662
- children: [/* @__PURE__ */ jsxs("span", { children: [
16663
- "Restored the version from ",
16664
- restored,
16665
- " into the draft."
16666
- ] }), /* @__PURE__ */ jsx("button", {
16667
- type: "button",
16668
- class: "bm-tertiary",
16669
- onClick: () => {
16670
- onUndo();
16671
- setRestored(null);
16672
- },
16673
- children: "Undo"
16674
- })]
16675
- }),
16676
- /* @__PURE__ */ jsxs("div", {
16677
- class: "bm-changes-list",
16678
- children: [
16679
- failed && /* @__PURE__ */ jsx("p", {
16680
- class: "bm-error",
16681
- children: "Could not load the saved versions."
16682
- }),
16683
- !failed && entries === null && /* @__PURE__ */ jsx("p", {
16684
- class: "bm-note",
16685
- children: "Loading…"
16686
- }),
16687
- entries !== null && entries.length === 0 && /* @__PURE__ */ jsx("p", {
16688
- class: "bm-note",
16689
- children: "Nothing saved yet. Every save keeps a copy here, newest first."
16690
- }),
16691
- days.map((group) => /* @__PURE__ */ jsxs("section", {
16692
- class: "bm-day",
16693
- "aria-label": group.day,
16694
- children: [/* @__PURE__ */ jsx("h3", {
16695
- class: "bm-changes-area",
16696
- children: group.day
16697
- }), /* @__PURE__ */ jsx("ul", {
16698
- class: "bm-versions",
16699
- children: group.items.map(({ entry, index }) => {
16700
- const isOpen = openId === entry.id;
16701
- const list = diffs[entry.id];
16702
- const stamp = formatVersionTime(entry.at);
16703
- const earliest = index === (entries?.length ?? 0) - 1;
16704
- return /* @__PURE__ */ jsxs("li", {
16705
- class: "bm-version",
16706
- children: [/* @__PURE__ */ jsxs("div", {
16707
- class: "bm-version-row",
16708
- children: [
16709
- /* @__PURE__ */ jsx("button", {
16710
- type: "button",
16711
- class: "bm-icon-btn",
16712
- "aria-expanded": isOpen,
16713
- "aria-label": `${isOpen ? "Hide" : "Show"} what changed in the version from ${stamp}`,
16714
- onClick: () => setOpenId(isOpen ? null : entry.id),
16715
- children: /* @__PURE__ */ jsx(Icon, {
16716
- name: isOpen ? "chevron-up" : "chevron-down",
16717
- size: 16
16718
- })
16719
- }),
16720
- /* @__PURE__ */ jsxs("button", {
16721
- type: "button",
16722
- class: "bm-tertiary bm-version-when",
16723
- onClick: () => setOpenId(isOpen ? null : entry.id),
16724
- children: [/* @__PURE__ */ jsxs("span", {
16725
- class: "bm-version-line",
16726
- children: [/* @__PURE__ */ jsx("span", {
16727
- class: "bm-version-rel",
16728
- children: versionAgo(entry.at) || stamp
16729
- }), /* @__PURE__ */ jsx("span", {
16730
- class: "bm-version-abs",
16731
- children: versionClock(entry.at)
16732
- })]
16733
- }), versionSummary(list) && /* @__PURE__ */ jsx("span", {
16734
- class: "bm-version-sum",
16735
- children: versionSummary(list)
16736
- })]
16737
- }),
16738
- index === 0 ? /* @__PURE__ */ jsx("span", {
16739
- class: "bm-badge bm-badge-on",
16740
- children: "current"
16741
- }) : /* @__PURE__ */ jsxs("button", {
16742
- type: "button",
16743
- class: "bm-restore",
16744
- "aria-label": `Restore the version from ${stamp}`,
16745
- onClick: () => void restore(entry),
16746
- children: [/* @__PURE__ */ jsx(Icon, {
16747
- name: "rotate-ccw",
16748
- size: 14
16749
- }), "Restore"]
16750
- })
16751
- ]
16752
- }), isOpen && /* @__PURE__ */ jsx("div", {
16753
- class: "bm-version-diff",
16754
- children: !list || list.length === 0 ? /* @__PURE__ */ jsx("p", {
16755
- class: "bm-note",
16756
- children: earliest ? "The earliest kept version, so there is nothing older to compare with." : list ? "No difference from the save before it." : "Loading…"
16757
- }) : groupChanges(list).map((area) => /* @__PURE__ */ jsxs("section", {
16758
- "aria-label": area.area,
16759
- children: [/* @__PURE__ */ jsx("h3", {
16760
- class: "bm-changes-area",
16761
- children: area.area
16762
- }), /* @__PURE__ */ jsx("ul", { children: area.entries.map((item) => /* @__PURE__ */ jsx(ChangeRow, {
16763
- item,
16764
- scope
16765
- }, `${item.field}:${item.kind}`)) })]
16766
- }, area.area))
16767
- })]
16768
- }, entry.id);
16769
- })
16770
- })]
16771
- }, group.day))
16772
- ]
16773
- }),
16774
- entries !== null && entries.length > 0 && /* @__PURE__ */ jsx("div", {
16775
- class: "bm-dialog-foot",
16776
- children: /* @__PURE__ */ jsxs("p", {
16777
- class: "bm-hint",
16778
- children: [
16779
- entries.length,
16780
- " of ",
16781
- VERSION_CAP,
16782
- " kept on this computer. Older versions drop off."
16783
- ]
16784
- })
16785
- })
16786
- ]
16787
- });
16788
- }
16789
- //#endregion
16790
- //#region src/ui/context.ts
16791
- const LinksContext = createContext({
16792
- pages: [],
16793
- currentSlug: "index",
16794
- anchors: [],
16795
- editLink: () => {}
16796
- });
16797
- const IssueContext = createContext([]);
16798
- /** Which props of the section being edited can be dropped. ValueEditor reads it to offer Remove, Add and "empty hides it". */
16799
- const OptionalContext = createContext({ content: void 0 });
16800
- /**
16801
- * What the schema of the section being edited says about its fields, by field key: fixed choices and their icons
16802
- * (ValueEditor shows a picker) and image fields (MissingField shows an image slot).
16803
- */
16804
- const FieldsContext = createContext({
16805
- choices: void 0,
16806
- icons: void 0,
16807
- images: void 0
16808
- });
16809
- //#endregion
16810
- //#region src/ui/image-field.tsx
16811
- const FIT_LABEL = {
16812
- cover: "Cover",
16813
- contain: "Contain",
16814
- auto: "Auto"
16815
- };
16816
- const FIT_HINT = {
16817
- cover: "Fills the frame and crops the overflow.",
16818
- contain: "Shows the whole image inside the frame.",
16819
- auto: "Keeps the image’s own size and aspect ratio."
16820
- };
16821
- const POSITION_LABEL = {
16822
- "top left": "Top left",
16823
- top: "Top",
16824
- "top right": "Top right",
16825
- left: "Left",
16826
- center: "Center",
16827
- right: "Right",
16828
- "bottom left": "Bottom left",
16829
- bottom: "Bottom",
16830
- "bottom right": "Bottom right"
16831
- };
16832
- /** Drop the keys that equal their default so saved JSON only holds real choices. */
16833
- function compact(next) {
16834
- const { fit, position, hidden, ...rest } = next;
16835
- return {
16836
- ...rest,
16837
- ...hidden === true ? { hidden } : {},
16838
- ...fit && fit !== "cover" ? { fit } : {},
16839
- ...position && position !== "center" ? { position } : {}
16840
- };
16841
- }
16842
- /**
16843
- * True when `src` is a local image whose file is gone. The dev route answers HEAD with 404 for those; remote URLs and
16844
- * placeholders are never "missing". Rechecks whenever the path changes.
16845
- */
16846
- function useMissingFile(src) {
16847
- const [missing, setMissing] = useState(false);
16848
- useEffect(() => {
16849
- const url = previewSrc(src);
16850
- if (!url.startsWith("/__bearminion/assets?")) {
16851
- setMissing(false);
16852
- return;
16853
- }
16854
- let current = true;
16855
- fetch(url, {
16856
- method: "HEAD",
16857
- cache: "no-store"
16858
- }).then((response) => {
16859
- if (current) setMissing(response.status === 404);
16860
- }).catch(() => {
16861
- if (current) setMissing(false);
16862
- });
16863
- return () => {
16864
- current = false;
16865
- };
16866
- }, [src]);
16867
- return missing;
16868
- }
16869
- function previewSrc(src) {
16870
- if (src === "" || src === "placeholder") return "";
16871
- if (/^https?:\/\//i.test(src) || src.startsWith("/")) return src;
16872
- return `/__bearminion/assets?src=${encodeURIComponent(src.replace(/^\//, ""))}`;
16873
- }
16874
- /** Only react to files. Dragging text or a link over a drop target is not an upload. */
16875
- function hasFiles(event) {
16876
- return Array.from(event.dataTransfer?.types ?? []).includes("Files");
16877
- }
16878
- function fileName(src) {
16879
- return src.split("/").pop() || src;
16880
- }
16881
- /** The tab last used in this page session, so a second pick starts where the first ended. */
16882
- let lastTab = null;
16883
- const ACCEPT = "image/png,image/jpeg,image/webp,image/gif,image/avif";
16884
- const FOCUSABLE = "button:not(:disabled), input:not(:disabled), [tabindex=\"0\"]";
16885
- /**
16886
- * One control for every image in the editor. Empty: a slot that opens the picker.
16887
- * Filled: thumbnail, file name, alt text, Change and Remove. The picker is a modal
16888
- * with an Upload tab (drop or browse) and a Library tab (pick or delete).
16889
- */
16890
- function ImageField({ label, path, value, images, withAlt = true, layout = true, hideable = false, onChange, onUploaded, onDeleted }) {
16891
- const [open, setOpen] = useState(false);
16892
- const [error, setError] = useState("");
16893
- const [over, setOver] = useState(false);
16894
- const root = useRef(null);
16895
- const opener = useRef(null);
16896
- const src = typeof value?.src === "string" ? value.src : "";
16897
- const alt = typeof value?.alt === "string" ? value.alt : "";
16898
- const fit = isImageFit(value?.fit) ? value.fit : DEFAULT_IMAGE_FIT;
16899
- const position = isImagePosition(value?.position) ? value.position : DEFAULT_IMAGE_POSITION;
16900
- const showLayout = layout && withAlt;
16901
- const hidden = hideable && value?.hidden === true;
16902
- const current = {
16903
- src,
16904
- alt,
16905
- fit,
16906
- position,
16907
- ...hidden ? { hidden } : {}
16908
- };
16909
- /** Emit the whole image object. A new file or alt keeps the fit and position already chosen. */
16910
- const emit = (patch) => onChange(compact({
16911
- ...current,
16912
- ...patch
16913
- }));
16914
- const empty = src === "" || src === "placeholder";
16915
- const shown = previewSrc(src);
16916
- const missing = useMissingFile(empty ? "" : src);
16917
- const fallbackAlt = withAlt ? "Image" : "";
16918
- function openPicker(trigger) {
16919
- opener.current = trigger;
16920
- setError("");
16921
- setOpen(true);
16604
+ const opener = useRef(null);
16605
+ const src = typeof value?.src === "string" ? value.src : "";
16606
+ const alt = typeof value?.alt === "string" ? value.alt : "";
16607
+ const fit = isImageFit(value?.fit) ? value.fit : DEFAULT_IMAGE_FIT;
16608
+ const position = isImagePosition(value?.position) ? value.position : DEFAULT_IMAGE_POSITION;
16609
+ const showLayout = layout && withAlt;
16610
+ const hidden = hideable && value?.hidden === true;
16611
+ const current = {
16612
+ src,
16613
+ alt,
16614
+ fit,
16615
+ position,
16616
+ ...hidden ? { hidden } : {}
16617
+ };
16618
+ /** Emit the whole image object. A new file or alt keeps the fit and position already chosen. */
16619
+ const emit = (patch) => onChange(compact({
16620
+ ...current,
16621
+ ...patch
16622
+ }));
16623
+ const empty = src === "" || src === "placeholder";
16624
+ const shown = previewSrc(src);
16625
+ const missing = useMissingFile(empty ? "" : src);
16626
+ const fallbackAlt = withAlt ? "Image" : "";
16627
+ function openPicker(trigger) {
16628
+ opener.current = trigger;
16629
+ setError("");
16630
+ setOpen(true);
16922
16631
  }
16923
16632
  function closePicker() {
16924
16633
  setOpen(false);
@@ -17423,21 +17132,47 @@ function ImagePickerModal({ src, images, onPick, onUploaded, onDeleted, onClose
17423
17132
  })]
17424
17133
  });
17425
17134
  }
17426
- //#endregion
17427
- //#region src/ui/forms/field-errors.tsx
17428
- /** Validation messages for one field, under its control. */
17429
- function FieldErrors({ issues }) {
17430
- if (issues.length === 0) return null;
17431
- return /* @__PURE__ */ jsx(Fragment$1, { children: issues.map((issue) => /* @__PURE__ */ jsx("span", {
17432
- class: "bm-error",
17433
- children: issue.message
17434
- }, `${issue.path}:${issue.message}`)) });
17435
- }
17436
- /** The issues reported for exactly this path. */
17437
- function issuesFor(issues, path) {
17438
- if (!path) return [];
17439
- return issues.filter((issue) => issue.path === path);
17440
- }
17135
+ //#endregion
17136
+ //#region src/ui/forms/field-errors.tsx
17137
+ /** Validation messages for one field, under its control. */
17138
+ function FieldErrors({ issues }) {
17139
+ if (issues.length === 0) return null;
17140
+ return /* @__PURE__ */ jsx(Fragment$1, { children: issues.map((issue) => /* @__PURE__ */ jsx("span", {
17141
+ class: "bm-error",
17142
+ children: issue.message
17143
+ }, `${issue.path}:${issue.message}`)) });
17144
+ }
17145
+ /** The issues reported for exactly this path. */
17146
+ function issuesFor(issues, path) {
17147
+ if (!path) return [];
17148
+ return issues.filter((issue) => issue.path === path);
17149
+ }
17150
+ //#endregion
17151
+ //#region src/ui/forms/segmented.tsx
17152
+ /** Segmented control for a short list of exclusive choices. */
17153
+ function Segmented({ label, value, options, onChange, hideLabel }) {
17154
+ const values = options.map((option) => option.value);
17155
+ return /* @__PURE__ */ jsxs("div", {
17156
+ class: "bm-field",
17157
+ children: [!hideLabel && /* @__PURE__ */ jsx("span", {
17158
+ class: "bm-label",
17159
+ children: label
17160
+ }), /* @__PURE__ */ jsx("div", {
17161
+ class: "bm-segmented",
17162
+ role: "radiogroup",
17163
+ "aria-label": label,
17164
+ onKeyDown: (event) => stepRadio(event, values, value, onChange),
17165
+ children: options.map((option) => /* @__PURE__ */ jsx("button", {
17166
+ type: "button",
17167
+ role: "radio",
17168
+ "aria-checked": value === option.value,
17169
+ tabIndex: value === option.value ? 0 : -1,
17170
+ onClick: () => onChange(option.value),
17171
+ children: option.label
17172
+ }, option.value))
17173
+ })]
17174
+ });
17175
+ }
17441
17176
  /** `split` → "Split", `top-left` → "Top left". Values such as `16:9` stay as they are. */
17442
17177
  function choiceLabel(value) {
17443
17178
  const words = value.replace(/[_-]+/g, " ").trim();
@@ -17920,41 +17655,544 @@ function Field({ label, value, onChange, multiline = false, path, prefix, hint,
17920
17655
  onInput: (event) => onChange(event.currentTarget.value),
17921
17656
  onSelect: onSelectRange ? (event) => onSelectRange(event.currentTarget.selectionStart ?? 0, event.currentTarget.selectionEnd ?? 0) : void 0
17922
17657
  });
17923
- return /* @__PURE__ */ jsxs("label", {
17924
- class: "bm-label",
17658
+ return /* @__PURE__ */ jsxs("label", {
17659
+ class: "bm-label",
17660
+ children: [
17661
+ /* @__PURE__ */ jsxs("span", {
17662
+ class: "bm-label-row",
17663
+ children: [/* @__PURE__ */ jsxs("span", {
17664
+ class: "bm-label-text",
17665
+ children: [label, hint && /* @__PURE__ */ jsx(Info, {
17666
+ id: hintId,
17667
+ text: hint,
17668
+ label: `About ${label}`
17669
+ })]
17670
+ }), meta && /* @__PURE__ */ jsx("span", {
17671
+ class: "bm-meta-tag",
17672
+ children: meta
17673
+ })]
17674
+ }),
17675
+ prefix ? /* @__PURE__ */ jsxs("span", {
17676
+ class: "bm-prefix-wrap",
17677
+ children: [/* @__PURE__ */ jsx("span", {
17678
+ class: "bm-prefix",
17679
+ "aria-hidden": "true",
17680
+ children: prefix
17681
+ }), control]
17682
+ }) : control,
17683
+ /* @__PURE__ */ jsx(FieldErrors, { issues })
17684
+ ]
17685
+ });
17686
+ }
17687
+ /** An array item's keys, plus the optional ones it has dropped, in the order the sample item lists them. */
17688
+ function orderItemKeys(item, path, content) {
17689
+ const parts = path.replace(/^sections\.\d+\.props\./, "").split(".");
17690
+ const dropped = parts.length === 2 && /^\d+$/.test(parts[1] ?? "") ? content?.items?.[parts[0] ?? ""] ?? [] : [];
17691
+ return orderContentKeys(Object.keys(item), dropped, Object.keys(item));
17692
+ }
17693
+ //#endregion
17694
+ //#region src/ui/dialogs/consent-dialog.tsx
17695
+ const KEYS = [
17696
+ "title",
17697
+ "body",
17698
+ "accept",
17699
+ "reject",
17700
+ "settings",
17701
+ "policyLabel",
17702
+ "policyHref"
17703
+ ];
17704
+ function startDraft(consent) {
17705
+ const copy = consentCopy(consent);
17706
+ return {
17707
+ title: copy.title,
17708
+ body: copy.body,
17709
+ accept: copy.accept,
17710
+ reject: copy.reject,
17711
+ settings: copy.settings,
17712
+ policyLabel: copy.policyLabel,
17713
+ policyHref: copy.policyHref ?? ""
17714
+ };
17715
+ }
17716
+ /**
17717
+ * What the draft saves: only the texts that differ from the theme's own, so a site that never changed a
17718
+ * text keeps following the default. An emptied field goes back to the default too.
17719
+ */
17720
+ function savedConsentText(draft) {
17721
+ const saved = {};
17722
+ for (const key of KEYS) {
17723
+ const value = draft[key].trim();
17724
+ const fallback = key === "policyHref" ? "" : CONSENT_COPY[key];
17725
+ if (value !== "" && value !== fallback) saved[key] = value;
17726
+ }
17727
+ return saved;
17728
+ }
17729
+ /**
17730
+ * The words of the cookie banner. It edits a copy: Apply writes it to the site draft in one step, Cancel and
17731
+ * Escape drop it. On and off lives in the sidebar, so this dialog never changes it.
17732
+ */
17733
+ function ConsentDialog({ consent, reopen: startReopen, onApply, onClose }) {
17734
+ const root = useRef(null);
17735
+ const [draft, setDraft] = useState(() => startDraft(consent));
17736
+ const [reopen, setReopen] = useState(startReopen);
17737
+ const saved = savedConsentText(draft);
17738
+ const issues = consentTextIssues(saved);
17739
+ const valid = Object.keys(issues).length === 0;
17740
+ const preview = consentCopy(saved);
17741
+ useEffect(() => {
17742
+ root.current?.querySelector("input, textarea")?.focus();
17743
+ }, []);
17744
+ const set = (key) => (value) => setDraft((current) => ({
17745
+ ...current,
17746
+ [key]: value
17747
+ }));
17748
+ const field = (key, label, extra = {}) => /* @__PURE__ */ jsx(Field, {
17749
+ label,
17750
+ value: draft[key],
17751
+ onChange: set(key),
17752
+ hint: issues[key] ? void 0 : extra.hint,
17753
+ multiline: extra.multiline,
17754
+ mono: extra.mono,
17755
+ meta: extra.limit ? `${draft[key].length} / ${extra.limit}` : void 0
17756
+ });
17757
+ return /* @__PURE__ */ jsx("div", {
17758
+ class: "bm-scrim",
17759
+ children: /* @__PURE__ */ jsxs("div", {
17760
+ class: "bm-dialog bm-consent",
17761
+ role: "dialog",
17762
+ "aria-modal": "true",
17763
+ "aria-label": "Edit cookie banner",
17764
+ ref: root,
17765
+ children: [
17766
+ /* @__PURE__ */ jsxs("div", {
17767
+ class: "bm-dialog-head",
17768
+ children: [/* @__PURE__ */ jsxs("div", {
17769
+ class: "bm-dialog-heading",
17770
+ children: [/* @__PURE__ */ jsx("h2", {
17771
+ class: "bm-dialog-title",
17772
+ children: "Cookie banner"
17773
+ }), /* @__PURE__ */ jsx("p", {
17774
+ class: "bm-dialog-sub",
17775
+ children: "Applied to the site draft. Nothing is written until you save."
17776
+ })]
17777
+ }), /* @__PURE__ */ jsx(DialogClose, { onClose })]
17778
+ }),
17779
+ /* @__PURE__ */ jsxs("div", {
17780
+ class: "bm-consent-body",
17781
+ children: [
17782
+ /* @__PURE__ */ jsxs("div", {
17783
+ class: "bm-consent-preview",
17784
+ "aria-hidden": "true",
17785
+ children: [
17786
+ /* @__PURE__ */ jsx("p", {
17787
+ class: "bm-consent-preview-title",
17788
+ children: preview.title
17789
+ }),
17790
+ /* @__PURE__ */ jsxs("p", {
17791
+ class: "bm-consent-preview-text",
17792
+ children: [preview.body, preview.policyHref && /* @__PURE__ */ jsxs("span", {
17793
+ class: "bm-consent-preview-link",
17794
+ children: [" ", preview.policyLabel]
17795
+ })]
17796
+ }),
17797
+ /* @__PURE__ */ jsxs("div", {
17798
+ class: "bm-consent-preview-buttons",
17799
+ children: [/* @__PURE__ */ jsx("span", { children: preview.accept }), /* @__PURE__ */ jsx("span", { children: preview.reject })]
17800
+ })
17801
+ ]
17802
+ }),
17803
+ /* @__PURE__ */ jsxs("div", {
17804
+ class: "bm-stack",
17805
+ children: [
17806
+ /* @__PURE__ */ jsx("p", {
17807
+ class: "bm-group",
17808
+ children: "Text"
17809
+ }),
17810
+ field("title", "Title", { limit: CONSENT_LIMITS.title }),
17811
+ field("body", "Message", {
17812
+ multiline: true,
17813
+ limit: CONSENT_LIMITS.body
17814
+ }),
17815
+ /* @__PURE__ */ jsxs("div", {
17816
+ class: "bm-row-split",
17817
+ children: [field("accept", "Accept button"), field("reject", "Reject button")]
17818
+ })
17819
+ ]
17820
+ }),
17821
+ /* @__PURE__ */ jsxs("div", {
17822
+ class: "bm-stack",
17823
+ children: [
17824
+ /* @__PURE__ */ jsx("p", {
17825
+ class: "bm-group",
17826
+ children: "Privacy policy"
17827
+ }),
17828
+ field("policyHref", "Policy page", {
17829
+ hint: "Optional. A page on this site, such as /privacy, or a full address. Leave empty for no link.",
17830
+ mono: true
17831
+ }),
17832
+ field("policyLabel", "Policy link text")
17833
+ ]
17834
+ }),
17835
+ /* @__PURE__ */ jsxs("div", {
17836
+ class: "bm-stack",
17837
+ children: [
17838
+ /* @__PURE__ */ jsx("p", {
17839
+ class: "bm-group",
17840
+ children: "Changing the choice"
17841
+ }),
17842
+ /* @__PURE__ */ jsx(Segmented, {
17843
+ label: "Visitors reopen it with",
17844
+ value: reopen,
17845
+ options: [{
17846
+ value: "footer",
17847
+ label: "Footer link"
17848
+ }, {
17849
+ value: "icon",
17850
+ label: "Corner icon"
17851
+ }],
17852
+ onChange: (value) => setReopen(value === "icon" ? "icon" : "footer")
17853
+ }),
17854
+ field("settings", reopen === "icon" ? "Icon label" : "Footer link text", { hint: reopen === "icon" ? "A small cookie icon in the bottom-left corner, shown once the banner is closed. The label is read out by screen readers." : "The link stays in the footer after visitors choose, so they can change their mind." })
17855
+ ]
17856
+ }),
17857
+ Object.entries(issues).map(([key, message]) => /* @__PURE__ */ jsxs("span", {
17858
+ class: "bm-error",
17859
+ role: "alert",
17860
+ children: [
17861
+ KEY_LABEL[key],
17862
+ ": ",
17863
+ message
17864
+ ]
17865
+ }, key))
17866
+ ]
17867
+ }),
17868
+ /* @__PURE__ */ jsxs("div", {
17869
+ class: "bm-actions",
17870
+ children: [/* @__PURE__ */ jsx("button", {
17871
+ type: "button",
17872
+ class: "bm-primary",
17873
+ disabled: !valid,
17874
+ onClick: () => onApply(saved, reopen),
17875
+ children: "Apply"
17876
+ }), /* @__PURE__ */ jsx("button", {
17877
+ type: "button",
17878
+ class: "bm-tertiary",
17879
+ onClick: onClose,
17880
+ children: "Cancel"
17881
+ })]
17882
+ })
17883
+ ]
17884
+ })
17885
+ });
17886
+ }
17887
+ const KEY_LABEL = {
17888
+ title: "Title",
17889
+ body: "Message",
17890
+ accept: "Accept button",
17891
+ reject: "Reject button",
17892
+ settings: "Footer link text or icon label",
17893
+ policyLabel: "Policy link text",
17894
+ policyHref: "Policy page"
17895
+ };
17896
+ //#endregion
17897
+ //#region src/ui/dialogs/history-dialog.tsx
17898
+ function formatVersionTime(iso) {
17899
+ const date = new Date(iso);
17900
+ if (Number.isNaN(date.getTime())) return iso;
17901
+ return date.toLocaleString(void 0, {
17902
+ month: "short",
17903
+ day: "numeric",
17904
+ hour: "2-digit",
17905
+ minute: "2-digit"
17906
+ });
17907
+ }
17908
+ const VERSION_CAP = 50;
17909
+ function startOfDay(date) {
17910
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
17911
+ }
17912
+ /** Today / Yesterday / "12 Mar" (with the year when it is not this one). */
17913
+ function versionDay(iso, now = /* @__PURE__ */ new Date()) {
17914
+ const date = new Date(iso);
17915
+ if (Number.isNaN(date.getTime())) return iso;
17916
+ const days = Math.round((startOfDay(now) - startOfDay(date)) / 864e5);
17917
+ if (days === 0) return "Today";
17918
+ if (days === 1) return "Yesterday";
17919
+ return date.toLocaleDateString(void 0, {
17920
+ day: "numeric",
17921
+ month: "short",
17922
+ ...date.getFullYear() === now.getFullYear() ? {} : { year: "numeric" }
17923
+ });
17924
+ }
17925
+ function versionClock(iso) {
17926
+ const date = new Date(iso);
17927
+ return Number.isNaN(date.getTime()) ? "" : date.toLocaleTimeString(void 0, {
17928
+ hour: "2-digit",
17929
+ minute: "2-digit",
17930
+ hour12: false
17931
+ });
17932
+ }
17933
+ /** "just now", "2 min ago", "3 h ago"; older than a day shows only the clock time. */
17934
+ function versionAgo(iso, now = Date.now()) {
17935
+ const then = new Date(iso).getTime();
17936
+ if (Number.isNaN(then)) return "";
17937
+ const minutes = Math.max(0, Math.round((now - then) / 6e4));
17938
+ if (minutes < 1) return "just now";
17939
+ if (minutes < 60) return `${minutes} min ago`;
17940
+ const hours = Math.round(minutes / 60);
17941
+ return hours < 24 ? `${hours} h ago` : versionClock(iso);
17942
+ }
17943
+ /** "title, hero › heading +2": the first changed fields of one save, for the collapsed row. */
17944
+ function versionSummary(list) {
17945
+ if (!list || list.length === 0) return "";
17946
+ const names = [...new Set(list.map((item) => item.field))];
17947
+ return names.length <= 3 ? names.join(", ") : `${names.slice(0, 3).join(", ")} +${names.length - 3}`;
17948
+ }
17949
+ /**
17950
+ * Saved versions of this page and of the site, newest first and grouped by day. A version shows what that save changed,
17951
+ * and Restore loads it into the draft. Nothing is written until the next save, and the restore can be undone from here.
17952
+ */
17953
+ function HistoryDialog({ slug, labels, page, onRestore, onUndo, onClose }) {
17954
+ const root = useRef(null);
17955
+ useDialogFocus(root);
17956
+ const [scope, setScope] = useState("page");
17957
+ const [entries, setEntries] = useState(null);
17958
+ const [diffs, setDiffs] = useState({});
17959
+ const [failed, setFailed] = useState(false);
17960
+ const [openId, setOpenId] = useState(null);
17961
+ const [restored, setRestored] = useState(null);
17962
+ const base = `${scope}:${slug}`;
17963
+ useEffect(() => {
17964
+ let live = true;
17965
+ setEntries(null);
17966
+ setDiffs({});
17967
+ setOpenId(null);
17968
+ setRestored(null);
17969
+ setFailed(false);
17970
+ const load = async () => {
17971
+ const listed = await listHistory(scope, slug);
17972
+ if (!listed.ok) throw new Error(listed.message);
17973
+ const body = listed.value;
17974
+ if (!live) return;
17975
+ setEntries(body.entries);
17976
+ const data = await Promise.all(body.entries.map(async (entry) => {
17977
+ const version = await getHistoryVersion(scope, slug, entry.id);
17978
+ return version.ok ? version.value : null;
17979
+ }));
17980
+ if (!live) return;
17981
+ const next = {};
17982
+ body.entries.forEach((entry, index) => {
17983
+ const after = data[index];
17984
+ const before = data[index + 1];
17985
+ if (after === null || before === null || before === void 0) return;
17986
+ next[entry.id] = scope === "page" ? describePageChanges(before, after, labels) : describeSiteChanges(before, after);
17987
+ });
17988
+ setDiffs(next);
17989
+ };
17990
+ load().catch(() => live && setFailed(true));
17991
+ return () => {
17992
+ live = false;
17993
+ };
17994
+ }, [base]);
17995
+ async function restore(entry) {
17996
+ const version = await getHistoryVersion(scope, slug, entry.id);
17997
+ if (!version.ok) {
17998
+ setFailed(true);
17999
+ return;
18000
+ }
18001
+ const when = formatVersionTime(entry.at);
18002
+ onRestore(scope, version.value, when);
18003
+ setRestored(when);
18004
+ }
18005
+ const days = [];
18006
+ entries?.forEach((entry, index) => {
18007
+ const day = versionDay(entry.at);
18008
+ const last = days[days.length - 1];
18009
+ if (last && last.day === day) last.items.push({
18010
+ entry,
18011
+ index
18012
+ });
18013
+ else days.push({
18014
+ day,
18015
+ items: [{
18016
+ entry,
18017
+ index
18018
+ }]
18019
+ });
18020
+ });
18021
+ return /* @__PURE__ */ jsxs("div", {
18022
+ class: "bm-dialog bm-changes",
18023
+ role: "dialog",
18024
+ "aria-modal": "true",
18025
+ "aria-label": "Version history",
18026
+ ref: root,
18027
+ style: "top:12%;left:50%;transform:translateX(-50%);",
17925
18028
  children: [
17926
- /* @__PURE__ */ jsxs("span", {
17927
- class: "bm-label-row",
17928
- children: [/* @__PURE__ */ jsxs("span", {
17929
- class: "bm-label-text",
17930
- children: [label, hint && /* @__PURE__ */ jsx(Info, {
17931
- id: hintId,
17932
- text: hint,
17933
- label: `About ${label}`
18029
+ /* @__PURE__ */ jsxs("div", {
18030
+ class: "bm-dialog-head",
18031
+ children: [/* @__PURE__ */ jsxs("div", {
18032
+ class: "bm-dialog-heading",
18033
+ children: [/* @__PURE__ */ jsxs("h2", {
18034
+ class: "bm-dialog-title",
18035
+ children: ["Version history", /* @__PURE__ */ jsx(Info, {
18036
+ label: "Where versions are kept",
18037
+ text: /* @__PURE__ */ jsxs(Fragment$1, { children: [
18038
+ "Versions are kept only on this computer, in ",
18039
+ /* @__PURE__ */ jsx("code", { children: ".editor/history" }),
18040
+ ". They are not in git and not on the published site. The newest ",
18041
+ VERSION_CAP,
18042
+ " stay. To clear them, stop the dev server and delete the ",
18043
+ /* @__PURE__ */ jsx("code", { children: ".editor" }),
18044
+ " folder in your project root."
18045
+ ] })
18046
+ })]
18047
+ }), /* @__PURE__ */ jsx("p", {
18048
+ class: "bm-dialog-sub",
18049
+ children: "Every save is kept. Restore loads a version into the draft; nothing is written until you save."
17934
18050
  })]
17935
- }), meta && /* @__PURE__ */ jsx("span", {
17936
- class: "bm-meta-tag",
17937
- children: meta
18051
+ }), /* @__PURE__ */ jsx(DialogClose, { onClose })]
18052
+ }),
18053
+ /* @__PURE__ */ jsx(Segmented, {
18054
+ hideLabel: true,
18055
+ label: "Scope",
18056
+ value: scope,
18057
+ options: [{
18058
+ value: "page",
18059
+ label: `Page "${page.title}"`
18060
+ }, {
18061
+ value: "site",
18062
+ label: "Site"
18063
+ }],
18064
+ onChange: (value) => setScope(value === "site" ? "site" : "page")
18065
+ }),
18066
+ restored !== null && /* @__PURE__ */ jsxs("div", {
18067
+ class: "bm-restored",
18068
+ role: "status",
18069
+ children: [/* @__PURE__ */ jsxs("span", { children: [
18070
+ "Restored the version from ",
18071
+ restored,
18072
+ " into the draft."
18073
+ ] }), /* @__PURE__ */ jsx("button", {
18074
+ type: "button",
18075
+ class: "bm-tertiary",
18076
+ onClick: () => {
18077
+ onUndo();
18078
+ setRestored(null);
18079
+ },
18080
+ children: "Undo"
17938
18081
  })]
17939
18082
  }),
17940
- prefix ? /* @__PURE__ */ jsxs("span", {
17941
- class: "bm-prefix-wrap",
17942
- children: [/* @__PURE__ */ jsx("span", {
17943
- class: "bm-prefix",
17944
- "aria-hidden": "true",
17945
- children: prefix
17946
- }), control]
17947
- }) : control,
17948
- /* @__PURE__ */ jsx(FieldErrors, { issues })
18083
+ /* @__PURE__ */ jsxs("div", {
18084
+ class: "bm-changes-list",
18085
+ children: [
18086
+ failed && /* @__PURE__ */ jsx("p", {
18087
+ class: "bm-error",
18088
+ children: "Could not load the saved versions."
18089
+ }),
18090
+ !failed && entries === null && /* @__PURE__ */ jsx("p", {
18091
+ class: "bm-note",
18092
+ children: "Loading…"
18093
+ }),
18094
+ entries !== null && entries.length === 0 && /* @__PURE__ */ jsx("p", {
18095
+ class: "bm-note",
18096
+ children: "Nothing saved yet. Every save keeps a copy here, newest first."
18097
+ }),
18098
+ days.map((group) => /* @__PURE__ */ jsxs("section", {
18099
+ class: "bm-day",
18100
+ "aria-label": group.day,
18101
+ children: [/* @__PURE__ */ jsx("h3", {
18102
+ class: "bm-changes-area",
18103
+ children: group.day
18104
+ }), /* @__PURE__ */ jsx("ul", {
18105
+ class: "bm-versions",
18106
+ children: group.items.map(({ entry, index }) => {
18107
+ const isOpen = openId === entry.id;
18108
+ const list = diffs[entry.id];
18109
+ const stamp = formatVersionTime(entry.at);
18110
+ const earliest = index === (entries?.length ?? 0) - 1;
18111
+ return /* @__PURE__ */ jsxs("li", {
18112
+ class: "bm-version",
18113
+ children: [/* @__PURE__ */ jsxs("div", {
18114
+ class: "bm-version-row",
18115
+ children: [
18116
+ /* @__PURE__ */ jsx("button", {
18117
+ type: "button",
18118
+ class: "bm-icon-btn",
18119
+ "aria-expanded": isOpen,
18120
+ "aria-label": `${isOpen ? "Hide" : "Show"} what changed in the version from ${stamp}`,
18121
+ onClick: () => setOpenId(isOpen ? null : entry.id),
18122
+ children: /* @__PURE__ */ jsx(Icon, {
18123
+ name: isOpen ? "chevron-up" : "chevron-down",
18124
+ size: 16
18125
+ })
18126
+ }),
18127
+ /* @__PURE__ */ jsxs("button", {
18128
+ type: "button",
18129
+ class: "bm-tertiary bm-version-when",
18130
+ onClick: () => setOpenId(isOpen ? null : entry.id),
18131
+ children: [/* @__PURE__ */ jsxs("span", {
18132
+ class: "bm-version-line",
18133
+ children: [/* @__PURE__ */ jsx("span", {
18134
+ class: "bm-version-rel",
18135
+ children: versionAgo(entry.at) || stamp
18136
+ }), /* @__PURE__ */ jsx("span", {
18137
+ class: "bm-version-abs",
18138
+ children: versionClock(entry.at)
18139
+ })]
18140
+ }), versionSummary(list) && /* @__PURE__ */ jsx("span", {
18141
+ class: "bm-version-sum",
18142
+ children: versionSummary(list)
18143
+ })]
18144
+ }),
18145
+ index === 0 ? /* @__PURE__ */ jsx("span", {
18146
+ class: "bm-badge bm-badge-on",
18147
+ children: "current"
18148
+ }) : /* @__PURE__ */ jsxs("button", {
18149
+ type: "button",
18150
+ class: "bm-restore",
18151
+ "aria-label": `Restore the version from ${stamp}`,
18152
+ onClick: () => void restore(entry),
18153
+ children: [/* @__PURE__ */ jsx(Icon, {
18154
+ name: "rotate-ccw",
18155
+ size: 14
18156
+ }), "Restore"]
18157
+ })
18158
+ ]
18159
+ }), isOpen && /* @__PURE__ */ jsx("div", {
18160
+ class: "bm-version-diff",
18161
+ children: !list || list.length === 0 ? /* @__PURE__ */ jsx("p", {
18162
+ class: "bm-note",
18163
+ children: earliest ? "The earliest kept version, so there is nothing older to compare with." : list ? "No difference from the save before it." : "Loading…"
18164
+ }) : groupChanges(list).map((area) => /* @__PURE__ */ jsxs("section", {
18165
+ "aria-label": area.area,
18166
+ children: [/* @__PURE__ */ jsx("h3", {
18167
+ class: "bm-changes-area",
18168
+ children: area.area
18169
+ }), /* @__PURE__ */ jsx("ul", { children: area.entries.map((item) => /* @__PURE__ */ jsx(ChangeRow, {
18170
+ item,
18171
+ scope
18172
+ }, `${item.field}:${item.kind}`)) })]
18173
+ }, area.area))
18174
+ })]
18175
+ }, entry.id);
18176
+ })
18177
+ })]
18178
+ }, group.day))
18179
+ ]
18180
+ }),
18181
+ entries !== null && entries.length > 0 && /* @__PURE__ */ jsx("div", {
18182
+ class: "bm-dialog-foot",
18183
+ children: /* @__PURE__ */ jsxs("p", {
18184
+ class: "bm-hint",
18185
+ children: [
18186
+ entries.length,
18187
+ " of ",
18188
+ VERSION_CAP,
18189
+ " kept on this computer. Older versions drop off."
18190
+ ]
18191
+ })
18192
+ })
17949
18193
  ]
17950
18194
  });
17951
18195
  }
17952
- /** An array item's keys, plus the optional ones it has dropped, in the order the sample item lists them. */
17953
- function orderItemKeys(item, path, content) {
17954
- const parts = path.replace(/^sections\.\d+\.props\./, "").split(".");
17955
- const dropped = parts.length === 2 && /^\d+$/.test(parts[1] ?? "") ? content?.items?.[parts[0] ?? ""] ?? [] : [];
17956
- return orderContentKeys(Object.keys(item), dropped, Object.keys(item));
17957
- }
17958
18196
  //#endregion
17959
18197
  //#region src/ui/forms/serp-preview.tsx
17960
18198
  /** Address as a search result shows it: no scheme, no `www.`, no trailing slash. Without a site URL, the path alone. */
@@ -18341,6 +18579,25 @@ function SessionDialog({ editor, dialog }) {
18341
18579
  onClose: close
18342
18580
  });
18343
18581
  }
18582
+ case "consent": {
18583
+ const site = doc.site.value;
18584
+ if (!site) return null;
18585
+ return /* @__PURE__ */ jsx(ConsentDialog, {
18586
+ consent: consentTextOf(site),
18587
+ reopen: consentReopenOf(site),
18588
+ onApply: (consent, reopen) => {
18589
+ const enabled = getAt(site, "consent.enabled");
18590
+ const next = {
18591
+ ...enabled === void 0 ? {} : { enabled },
18592
+ ...reopen === "icon" ? { reopen } : {},
18593
+ ...consent
18594
+ };
18595
+ edits.writeField("consent", Object.keys(next).length > 0 ? next : void 0);
18596
+ close();
18597
+ },
18598
+ onClose: close
18599
+ });
18600
+ }
18344
18601
  case "discard": return /* @__PURE__ */ jsx(ConfirmDialog, {
18345
18602
  label: "Discard changes",
18346
18603
  body: "Throw away every unsaved change to this page and the site, and reload both from the saved files?",
@@ -19708,7 +19965,7 @@ function AdvancedLink({ edit }) {
19708
19965
  }
19709
19966
  //#endregion
19710
19967
  //#region src/ui/editor.css?raw
19711
- var editor_default = "/*\n * Editor styles. They live in a shadow root, so they never meet the site's Tailwind layer.\n * The editor is always light. Tokens and values follow the v4 editor design handoff.\n * The short names (--ink, --line, --accent ...) alias the --bm-* tokens so older rules read the same.\n */\n:host {\n all: initial;\n\n /* ---------- v4 tokens (editor-tokens.css) ---------- */\n --bm-font-ui: \"Bricolage Grotesque Variable\", \"Bricolage Grotesque\", ui-sans-serif, system-ui, sans-serif;\n --bm-font-mono: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, monospace;\n --bm-font-serif: \"Instrument Serif\", Georgia, serif;\n\n --bm-ink: oklch(0.21 0.012 255);\n --bm-label: oklch(0.3 0.01 255);\n --bm-section: oklch(0.42 0.01 255);\n --bm-help: oklch(0.47 0.01 255);\n --bm-muted: oklch(0.5 0.01 255);\n --bm-icon: oklch(0.55 0.01 255);\n --bm-info: oklch(0.6 0.01 255);\n\n --bm-fill: oklch(0.955 0.003 250);\n --bm-fill-hover: oklch(0.93 0.004 250);\n --bm-fill-soft: oklch(0.965 0.003 250);\n --bm-fill-nested: oklch(0.97 0.003 250);\n --bm-border: oklch(0.88 0.005 250);\n --bm-divider: oklch(0.93 0.004 250);\n --bm-tab-rule: oklch(0.92 0.004 250);\n\n --bm-primary: oklch(0.46 0.13 145);\n --bm-primary-hover: oklch(0.4 0.12 145);\n --bm-primary-ring: oklch(0.46 0.13 145 / 0.15);\n --bm-link: oklch(0.4 0.12 145);\n\n --bm-saved-bg: oklch(0.94 0.045 145);\n --bm-saved-fg: oklch(0.36 0.1 145);\n --bm-unsaved-bg: oklch(0.95 0.05 80);\n --bm-unsaved-fg: oklch(0.48 0.1 60);\n --bm-unsaved-dot: oklch(0.75 0.15 70);\n --bm-badge-green-bg: oklch(0.93 0.06 145);\n --bm-badge-green-fg: oklch(0.38 0.1 145);\n --bm-badge-amber-bg: oklch(0.95 0.04 75);\n --bm-badge-amber-fg: oklch(0.45 0.09 60);\n\n --bm-danger: oklch(0.55 0.19 25);\n --bm-danger-text: oklch(0.52 0.17 25);\n --bm-danger-icon: oklch(0.58 0.18 25);\n --bm-danger-soft: oklch(0.96 0.025 20);\n\n --bm-diff-del-bg: oklch(0.97 0.02 20);\n --bm-diff-del-fg: oklch(0.45 0.13 25);\n --bm-diff-add-bg: oklch(0.96 0.04 145);\n --bm-diff-add-fg: oklch(0.34 0.1 145);\n\n --bm-switch-off: oklch(0.82 0.005 250);\n\n --bm-shadow-pop: 0 0 0 1px oklch(0.9 0.005 250), 0 16px 36px -16px oklch(0.2 0.02 255 / 0.35);\n --bm-shadow-dialog: 0 0 0 1px oklch(0.9 0.005 250), 0 24px 48px -24px oklch(0.2 0.02 255 / 0.35);\n --bm-shadow-segment-on: 0 1px 2px oklch(0 0 0 / 0.08), 0 0 0 1px oklch(0.9 0.005 250);\n\n /* ---------- aliases used by the rules below ---------- */\n --ink: var(--bm-ink);\n --ink-2: var(--bm-label);\n --muted: var(--bm-muted);\n --line: var(--bm-border);\n --line-soft: var(--bm-divider);\n --fill: var(--bm-fill);\n --fill-hover: var(--bm-fill-hover);\n --fill-soft: var(--bm-fill-soft);\n --accent: var(--bm-primary);\n --accent-hover: var(--bm-primary-hover);\n --accent-tint: oklch(0.96 0.03 145);\n --accent-ring: var(--bm-primary-ring);\n --warn-tint: var(--bm-unsaved-bg);\n --warn-ink: var(--bm-unsaved-fg);\n --warn-dot: var(--bm-unsaved-dot);\n --danger-hover: oklch(0.48 0.18 25);\n --danger-tint: var(--bm-danger-soft);\n --danger-ink: var(--bm-danger-text);\n --info-dot: oklch(0.6 0.15 255);\n --sans: var(--bm-font-ui);\n --mono: var(--bm-font-mono);\n --serif: var(--bm-font-serif);\n --shadow-pop: var(--bm-shadow-pop);\n}\n* {\n box-sizing: border-box;\n}\nbutton,\ninput,\nselect,\ntextarea {\n font: inherit;\n color: inherit;\n}\nbutton {\n cursor: pointer;\n}\n:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n\n/* On-page outlines */\n.bm-outline {\n position: fixed;\n pointer-events: none;\n border-radius: 6px;\n z-index: 1;\n}\n.bm-outline-section {\n border: 2px solid var(--accent);\n}\n.bm-outline-field {\n border: 2px solid var(--accent);\n background: oklch(0.46 0.13 145 / 0.08);\n}\n.bm-image-bar {\n flex-wrap: nowrap;\n left: auto;\n white-space: nowrap;\n}\n.bm-image-bar-group {\n display: flex;\n gap: 2px;\n}\n.bm-image-bar button[aria-pressed=\"true\"] {\n background: var(--bm-saved-bg);\n color: var(--bm-saved-fg);\n}\n.bm-image-bar-grid {\n display: grid;\n grid-template-columns: repeat(3, 9px);\n grid-template-rows: repeat(3, 9px);\n gap: 2px;\n align-self: center;\n padding: 0 4px;\n}\n.bm-image-bar .bm-pos-cell {\n width: 9px;\n height: 9px;\n /* `.bm-rich button` sets a 32px minimum for the bar's text buttons; the cells stay 9px. */\n min-width: 0;\n min-height: 0;\n padding: 0;\n border-radius: 2px;\n background: var(--line);\n}\n.bm-image-bar .bm-pos-cell:hover:not(:disabled) {\n background: var(--muted);\n}\n.bm-image-bar .bm-pos-cell[aria-pressed=\"true\"] {\n background: var(--accent);\n}\n.bm-image-bar .bm-pos-cell:disabled {\n opacity: 0.3;\n cursor: default;\n}\n.bm-outline-image {\n background: oklch(0.46 0.13 145 / 0.12);\n}\n.bm-outline-image::after {\n content: \"Change image\";\n position: absolute;\n top: 8px;\n left: 8px;\n padding: 4px 9px;\n border-radius: 6px;\n background: var(--accent);\n color: #fff;\n font: 500 11px / 1.3 var(--sans, system-ui, sans-serif);\n}\n\n.bm-toolbar,\n.bm-dock,\n.bm-exit-preview,\n.bm-sidebar,\n.bm-popover,\n.bm-dialog,\n.bm-rich,\n.bm-banner,\n.bm-scrim {\n pointer-events: auto;\n font-family: var(--sans);\n font-size: 13px;\n color: var(--ink);\n -webkit-font-smoothing: antialiased;\n}\n\n/*\n * Insert between sections. Three states:\n * idle / hover a solid line and a 28px circle; hover changes nothing.\n * open the picker is open: the line stays and a \"between A and B\" chip replaces the circle.\n */\n.bm-gap {\n position: fixed;\n z-index: 2;\n height: 0;\n pointer-events: none;\n}\n.bm-gap::before {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n height: 0;\n border-top: 2px solid var(--bm-primary);\n transform: translateY(-50%);\n}\n.bm-gap-add {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 999px;\n pointer-events: auto;\n cursor: pointer;\n white-space: nowrap;\n background: var(--bm-primary);\n color: #fff;\n box-shadow: 0 0 0 2px #fff;\n}\n.bm-gap-add .bm-icon {\n width: 14px;\n height: 14px;\n stroke-width: 2.4;\n}\n.bm-gap-add:focus-visible {\n outline: 2px solid var(--ink);\n outline-offset: 3px;\n}\n.bm-gap-chip {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n padding: 4px 10px;\n border-radius: 999px;\n background: #fff;\n color: var(--bm-ink);\n box-shadow: 0 0 0 1.5px var(--bm-primary);\n white-space: nowrap;\n pointer-events: none;\n font-size: 12px;\n font-weight: 500;\n}\n\n/* Light floating bars: section toolbar, rich text bar, heading format bar */\n.bm-toolbar,\n.bm-rich {\n position: fixed;\n z-index: 3;\n display: flex;\n gap: 2px;\n padding: 4px;\n border-radius: 12px;\n background: #fff;\n color: var(--ink);\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-toolbar button,\n.bm-rich button {\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: inherit;\n min-height: 32px;\n padding: 0 10px;\n font-size: 12px;\n font-weight: 500;\n}\n.bm-toolbar button:hover:not(:disabled),\n.bm-rich button:hover {\n background: var(--fill);\n}\n.bm-rich button[aria-pressed=\"true\"] {\n background: var(--bm-saved-bg);\n box-shadow: inset 0 0 0 1px oklch(0.46 0.13 145 / 0.4);\n}\n.bm-toolbar :focus-visible,\n.bm-rich :focus-visible {\n outline-color: var(--accent);\n}\n.bm-toolbar {\n align-items: center;\n max-width: calc(100vw - 16px);\n padding: 5px;\n}\n.bm-toolbar button {\n width: 34px;\n min-height: 34px;\n height: 34px;\n padding: 0;\n border-radius: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: oklch(0.4 0.01 255);\n}\n.bm-toolbar button:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n.bm-toolbar button:disabled {\n opacity: 0.35;\n cursor: default;\n}\n.bm-toolbar .bm-danger {\n color: var(--bm-danger-icon);\n}\n.bm-toolbar .bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-toolbar-active {\n box-shadow:\n 0 0 0 2px var(--bm-primary),\n 0 10px 24px -12px oklch(0.2 0.02 255 / 0.35);\n}\n.bm-toolbar-name {\n display: block;\n max-width: 16rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n padding: 0 12px 0 10px;\n}\n.bm-toolbar-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--bm-ink);\n}\n.bm-toolbar-anchor {\n font-family: var(--mono);\n font-size: 12px;\n font-weight: 400;\n color: var(--bm-muted);\n}\n.bm-sep {\n width: 1px;\n align-self: stretch;\n margin: 4px 2px;\n background: var(--line);\n}\n.bm-toolbar .bm-sep {\n align-self: center;\n height: 20px;\n margin: 0 4px;\n background: oklch(0.9 0.005 250);\n}\n.bm-icon {\n width: 16px;\n height: 16px;\n display: block;\n}\n.bm-rich {\n align-items: center;\n flex-wrap: wrap;\n max-width: calc(100vw - 16px);\n}\n.bm-rich button {\n min-height: 32px;\n min-width: 32px;\n}\n.bm-rich input {\n width: 168px;\n min-height: 30px;\n padding: 0 8px;\n border: 0;\n border-radius: 7px;\n background: var(--fill);\n color: var(--ink);\n font-size: 12px;\n}\n.bm-rich input:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--accent);\n}\n\n/* Heading format bar: each button shows \"Aa\" in its own weight or font over a mono caption. */\n.bm-rich.bm-format-bar {\n flex-wrap: nowrap;\n}\n.bm-rich.bm-format-bar button.bm-fmt {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n min-width: 42px;\n height: 48px;\n min-height: 48px;\n padding: 0 8px;\n border-radius: 8px;\n}\n.bm-fmt-sample {\n font-size: 15px;\n line-height: 1;\n color: var(--bm-ink);\n}\n.bm-fmt-caption {\n font-family: var(--mono);\n font-size: 9px;\n letter-spacing: 0.02em;\n color: var(--bm-muted);\n}\n.bm-rich.bm-format-bar button.bm-fmt[aria-pressed=\"true\"] {\n background: var(--bm-saved-bg);\n box-shadow: inset 0 0 0 1px oklch(0.46 0.13 145 / 0.4);\n}\n.bm-format-bar .bm-sep {\n align-self: stretch;\n margin: 6px 4px;\n}\n\n/* Light popovers: add menu, section picker, edit link */\n.bm-popover {\n position: fixed;\n z-index: 3;\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 180px;\n max-height: min(420px, calc(100vh - 16px));\n overflow: auto;\n padding: 6px;\n border-radius: 12px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-popover > button {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 34px;\n padding: 0 10px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n text-align: left;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-popover > button:hover {\n background: var(--fill);\n}\n\n/* Add section picker: wireframe cards */\n.bm-popover[aria-label=\"Add section\"][role=\"listbox\"] {\n gap: 14px;\n width: 640px;\n max-width: calc(100vw - 16px);\n max-height: calc(100vh - 16px);\n padding: 16px;\n border-radius: 14px;\n overflow: visible;\n box-shadow: var(--bm-shadow-dialog);\n}\n.bm-picker-head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.bm-picker-title {\n font-size: 17px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n.bm-picker-where {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n color: var(--bm-muted);\n}\n.bm-picker-grid {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 10px;\n max-height: 26rem;\n overflow-y: auto;\n padding: 2px 6px 2px 2px;\n margin-right: -6px;\n scrollbar-gutter: stable;\n}\n.bm-popover .bm-picker-grid > button {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: flex-start;\n gap: 6px;\n min-height: 0;\n padding: 8px 8px 10px;\n border: 1px solid oklch(0.9 0.005 250);\n border-radius: 10px;\n background: #fff;\n text-align: left;\n font-weight: 400;\n}\n.bm-popover .bm-picker-grid > button:hover {\n background: #fff;\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px oklch(0.46 0.13 145 / 0.12);\n}\n.bm-wire {\n position: relative;\n display: block;\n width: 100%;\n height: 76px;\n border-radius: 7px;\n background: oklch(0.97 0 0);\n overflow: hidden;\n}\n.bm-wire > span {\n position: absolute;\n display: block;\n}\n.bm-type-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 0 2px;\n}\n.bm-type-name {\n font-size: 14px;\n font-weight: 600;\n line-height: 1.25;\n color: var(--bm-ink);\n}\n.bm-type-variants {\n font-family: var(--mono);\n font-size: 10px;\n font-weight: 400;\n line-height: 1.35;\n white-space: nowrap;\n color: var(--muted);\n}\n.bm-type-desc {\n padding: 0 2px;\n font-size: 12px;\n line-height: 1.4;\n color: var(--bm-help);\n}\n.bm-picker-note {\n margin: 0;\n font-size: 12px;\n color: var(--bm-muted);\n}\n\n.bm-popover[aria-label=\"Edit link\"] {\n gap: 14px;\n padding: 16px;\n max-height: calc(100vh - 16px);\n}\n\n/* Dialogs and banners */\n.bm-dialog {\n position: fixed;\n z-index: 6;\n display: flex;\n flex-direction: column;\n gap: 16px;\n width: min(400px, calc(100vw - 32px));\n padding: 20px;\n border-radius: 14px;\n background: #fff;\n box-shadow: var(--bm-shadow-dialog);\n}\n.bm-dialog-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n.bm-dialog-heading {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.bm-dialog-sub {\n margin: 0;\n font-size: 13px;\n line-height: 1.4;\n color: var(--bm-help);\n}\n.bm-dialog .bm-dialog-x,\n.bm-popover .bm-dialog-x,\n.bm-modal .bm-dialog-x {\n flex: none;\n width: 32px;\n height: 32px;\n margin: -6px -8px -6px 0;\n background: transparent;\n color: var(--bm-icon);\n}\n.bm-dialog-title {\n margin: 0;\n font-size: 17px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--bm-ink);\n}\n.bm-popover .bm-dialog-title {\n font-size: 16px;\n}\n.bm-dialog .bm-note {\n color: var(--bm-label);\n font-size: 14px;\n line-height: 1.5;\n}\n.bm-dialog button,\n.bm-popover .bm-actions button,\n.bm-banner button {\n min-height: 38px;\n padding: 0 16px;\n border: 0;\n border-radius: 8px;\n background: var(--fill);\n font-size: 14px;\n font-weight: 400;\n}\n.bm-dialog button:hover:not(:disabled),\n.bm-popover .bm-actions button:hover:not(:disabled) {\n background: var(--fill-hover);\n}\n/* The primary action comes first in the DOM (focus lands on it); row-reverse shows it last, on the right. */\n.bm-actions {\n display: flex;\n flex-direction: row-reverse;\n justify-content: flex-start;\n align-items: center;\n gap: 8px;\n}\n.bm-dialog > .bm-actions,\n.bm-popover[aria-label=\"Edit link\"] > .bm-actions {\n padding-top: 12px;\n border-top: 1px solid var(--bm-divider);\n}\n.bm-dialog-foot {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 12px;\n border-top: 1px solid var(--bm-divider);\n}\n.bm-dialog-foot > .bm-hint {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n.bm-dialog-foot .bm-actions {\n flex: none;\n}\n\n/* Alert dialogs: [icon tile] [title / body / note] [x] */\n.bm-alert-main {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n.bm-alert-copy {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.bm-alert-body {\n margin: 0;\n font-size: 14px;\n line-height: 1.5;\n color: var(--bm-label);\n overflow-wrap: anywhere;\n}\n.bm-alert-body strong {\n font-weight: 600;\n color: var(--bm-ink);\n}\n.bm-alert-note {\n margin: 0;\n font-size: 12px;\n line-height: 1.45;\n color: var(--bm-muted);\n}\n.bm-tile {\n flex: none;\n display: grid;\n place-items: center;\n width: 36px;\n height: 36px;\n border-radius: 9px;\n}\n.bm-tile .bm-icon {\n width: 18px;\n height: 18px;\n}\n.bm-tile-warn {\n background: var(--bm-unsaved-bg);\n color: var(--bm-unsaved-fg);\n}\n.bm-tile-danger {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-tile-neutral {\n background: var(--bm-fill);\n color: var(--bm-label);\n}\n\n.bm-banner {\n position: fixed;\n z-index: 6;\n display: flex;\n align-items: center;\n gap: 12px;\n width: min(440px, calc(100vw - 32px));\n padding: 12px 14px;\n border-radius: 12px;\n box-shadow: 0 14px 34px -10px oklch(0.2 0.02 255 / 0.4);\n}\n.bm-banner button {\n min-height: 34px;\n padding: 0 14px;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-banner-ink {\n background: var(--ink);\n color: #fff;\n}\n.bm-banner-light {\n background: #fff;\n box-shadow: var(--shadow-pop);\n}\n.bm-banner-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.bm-banner-title {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.35;\n}\n.bm-banner-sub {\n margin: 0;\n font-size: 12px;\n line-height: 1.4;\n opacity: 0.7;\n}\n.bm-banner .bm-actions {\n flex: none;\n gap: 6px;\n}\n.bm-banner-ink button {\n min-height: 30px;\n padding: 0 12px;\n font-size: 12px;\n background: oklch(1 0 0 / 0.12);\n color: #fff;\n}\n.bm-banner-ink button:hover {\n background: oklch(1 0 0 / 0.2);\n}\n.bm-banner-ink .bm-primary {\n background: #fff;\n color: var(--ink);\n}\n.bm-banner-ink .bm-primary:hover {\n background: oklch(0.94 0.003 250);\n}\n.bm-banner-ink :focus-visible {\n outline-color: oklch(0.82 0.14 145);\n}\n.bm-dot-stale {\n background: oklch(0.7 0.18 25) !important;\n}\n.bm-dot-info {\n background: var(--info-dot) !important;\n}\n\n/* Closed editor. The dock sits where the sidebar header's controls sit: header padding (top 14, right 14) minus the dock's 7px padding. */\n.bm-dock {\n position: fixed;\n z-index: 5;\n top: 7px;\n right: 7px;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 7px 7px 10px;\n border-radius: 14px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-dot {\n flex: none;\n width: 8px;\n height: 8px;\n border-radius: 99px;\n background: oklch(0.72 0.17 145);\n}\n.bm-dot-dirty {\n background: var(--warn-dot);\n}\n\n/* Sidebar shell */\n.bm-sidebar {\n position: fixed;\n z-index: 4;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(440px, 100vw);\n display: flex;\n flex-direction: column;\n background: #fff;\n box-shadow:\n 0 0 0 1px var(--line),\n -24px 0 48px -24px oklch(0.2 0.02 255 / 0.25);\n}\n.bm-resize {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: col-resize;\n touch-action: none;\n z-index: 2;\n}\n.bm-resize:hover,\n.bm-resize:focus-visible {\n background: oklch(0.46 0.13 145 / 0.25);\n}\n.bm-resize:focus-visible {\n outline-offset: -2px;\n}\n\n.bm-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 14px 14px 16px;\n border-bottom: 1px solid var(--line-soft);\n}\n.bm-mark {\n flex: none;\n display: block;\n width: 28px;\n height: auto;\n aspect-ratio: 21 / 19;\n image-rendering: pixelated;\n user-select: none;\n}\n/* Bear, name and slogan. Takes the space the controls leave; the text fades out when it no longer fits. */\n.bm-brand {\n position: relative;\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.bm-head-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n transition: opacity 160ms ease;\n}\n.bm-brand-compact .bm-head-text {\n opacity: 0;\n}\n/* The same two lines, in a card left of the sidebar (over the page), level with the header, while the pointer is on\n the brand. 16px is the header's left padding: the card clears the sidebar edge by 10px. */\n.bm-brand-tip {\n position: absolute;\n z-index: 5;\n top: 50%;\n right: calc(100% + 16px + 10px);\n display: flex;\n flex-direction: column;\n padding: 8px 12px;\n border-radius: 10px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n white-space: nowrap;\n opacity: 0;\n transform: translate(4px, -50%);\n pointer-events: none;\n transition:\n opacity 120ms ease,\n transform 120ms ease;\n}\n.bm-brand-compact:hover .bm-brand-tip {\n opacity: 1;\n transform: translate(0, -50%);\n transition-delay: 120ms;\n}\n@media (prefers-reduced-motion: reduce) {\n .bm-head-text,\n .bm-brand-tip {\n transition: none;\n }\n}\n/* A ring with one open quarter that turns while a save is written and the page reloads. */\n.bm-spin {\n flex: none;\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: bm-spin 0.8s linear infinite;\n}\n@keyframes bm-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .bm-spin {\n animation: none;\n }\n}\n.bm-faces {\n display: grid;\n}\n.bm-face {\n grid-area: 1 / 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n white-space: nowrap;\n}\n.bm-face[hidden-face] {\n visibility: hidden;\n}\n.bm-save:disabled {\n opacity: 0.85;\n cursor: progress;\n}\n.bm-head-title {\n font-size: 15px;\n font-weight: 600;\n letter-spacing: -0.015em;\n /* The controls beside it never shrink, so a narrow sidebar cuts the name, not the buttons. */\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-head-sub {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-pill {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 10px;\n border-radius: 999px;\n background: var(--bm-saved-bg);\n color: var(--bm-saved-fg);\n font-size: 12px;\n font-weight: 500;\n}\n.bm-pill .bm-dot {\n width: 6px;\n height: 6px;\n background: var(--accent);\n}\n.bm-pill-dirty {\n background: var(--warn-tint);\n color: var(--warn-ink);\n}\n.bm-pill-dirty .bm-dot {\n background: var(--warn-dot);\n}\nbutton.bm-pill-btn {\n min-height: 0;\n padding: 0 10px;\n border: 0;\n border-radius: 999px;\n background: var(--warn-tint);\n color: var(--warn-ink);\n font-family: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n}\n:is(.bm-sidebar, .bm-dock) button.bm-pill-btn:hover:not(:disabled) {\n background: oklch(0.93 0.06 75);\n color: var(--warn-ink);\n}\nbutton.bm-pill-btn:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n.bm-dialog-wide {\n width: min(400px, calc(100vw - 32px));\n}\n.bm-dialog .bm-actions {\n flex-wrap: nowrap;\n}\n.bm-dialog .bm-actions button {\n flex: none;\n white-space: nowrap;\n}\n.bm-changes {\n width: min(540px, calc(100vw - 32px));\n}\n.bm-commit-files {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: min(34vh, 280px);\n overflow-y: auto;\n}\n.bm-commit-files label {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n cursor: pointer;\n}\n.bm-commit-mark {\n font:\n 600 11px / 1 ui-monospace,\n monospace;\n width: 18px;\n text-align: center;\n opacity: 0.7;\n}\n.bm-commit-msg {\n width: 100%;\n box-sizing: border-box;\n resize: vertical;\n font: inherit;\n font-size: 14px;\n padding: 8px 12px;\n border: 1px solid var(--line);\n border-radius: 8px;\n background: transparent;\n color: inherit;\n}\n\n/* Unsaved changes review and version history: groups, rows, diff lines */\n.bm-changes-list {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-height: 22rem;\n overflow-y: auto;\n margin: 0 -4px;\n padding: 0 4px;\n}\n.bm-changes-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-changes-area {\n margin: 0;\n display: flex;\n align-items: baseline;\n gap: 8px;\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--bm-section);\n}\n.bm-changes-file {\n font-weight: 400;\n letter-spacing: 0;\n text-transform: none;\n color: oklch(0.55 0.01 255);\n}\n.bm-changes-count {\n margin-left: auto;\n font-weight: 400;\n letter-spacing: 0;\n color: var(--bm-muted);\n}\n.bm-changes ul {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n overflow: hidden;\n}\n.bm-change {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 10px;\n font-size: 14px;\n line-height: 1.4;\n}\n.bm-change + .bm-change {\n border-top: 1px solid var(--bm-divider);\n}\n.bm-change-mark {\n flex: none;\n display: grid;\n place-items: center;\n width: 22px;\n height: 22px;\n border-radius: 6px;\n font-family: var(--mono);\n font-size: 13px;\n font-weight: 600;\n background: var(--bm-unsaved-bg);\n color: var(--bm-unsaved-fg);\n}\n.bm-change-added .bm-change-mark {\n background: var(--bm-badge-green-bg);\n color: var(--bm-badge-green-fg);\n}\n.bm-change-removed .bm-change-mark {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-text);\n}\n.bm-change-body {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.bm-change-field {\n font-weight: 500;\n color: var(--bm-ink);\n overflow-wrap: anywhere;\n}\n.bm-change-values {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n.bm-change-values del,\n.bm-change-values ins {\n display: flex;\n gap: 6px;\n min-width: 0;\n padding: 3px 7px;\n border-radius: 5px;\n text-decoration: none;\n font-size: 13px;\n}\n.bm-change-values del {\n background: var(--bm-diff-del-bg);\n color: var(--bm-diff-del-fg);\n}\n.bm-change-values ins {\n background: var(--bm-diff-add-bg);\n color: var(--bm-diff-add-fg);\n}\n.bm-change-values del::before {\n content: \"\\2212\";\n flex: none;\n font-family: var(--mono);\n}\n.bm-change-values ins::before {\n content: \"+\";\n flex: none;\n font-family: var(--mono);\n}\n.bm-change-values del > span,\n.bm-change-values ins > span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-change-values del > span {\n text-decoration: line-through;\n text-decoration-color: oklch(0.45 0.13 25 / 0.5);\n}\n.bm-changes-empty {\n margin: 0;\n padding: 24px 0;\n text-align: center;\n font-size: 14px;\n color: var(--bm-muted);\n}\n\n.bm-changes ul.bm-versions {\n gap: 0;\n}\n.bm-version {\n padding: 0;\n}\n.bm-version + .bm-version {\n border-top: 1px solid var(--bm-divider);\n}\n.bm-version-when strong {\n font-weight: 600;\n}\n.bm-tipped {\n position: relative;\n}\n.bm-tipped::after {\n content: attr(data-tip);\n position: absolute;\n right: calc(100% + 6px);\n top: 50%;\n transform: translateY(-50%);\n padding: 4px 8px;\n border-radius: 6px;\n background: var(--ink);\n color: #fff;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.3;\n white-space: nowrap;\n pointer-events: none;\n visibility: hidden;\n z-index: 5;\n}\n.bm-version-row > .bm-tipped:first-child::after {\n right: auto;\n left: calc(100% + 6px);\n}\n.bm-tipped:hover::after,\n.bm-tipped:focus-visible::after {\n visibility: visible;\n}\n.bm-version-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 8px 8px 10px;\n}\n.bm-version-when {\n flex: 1;\n min-width: 0;\n margin-right: auto;\n padding: 0 !important;\n min-height: 32px !important;\n font-weight: 500;\n display: flex !important;\n flex-direction: column;\n align-items: flex-start !important;\n justify-content: center;\n gap: 2px;\n text-align: left;\n}\n.bm-version-line {\n display: flex;\n align-items: baseline;\n gap: 8px;\n}\n.bm-version-sum {\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 400;\n color: var(--bm-help);\n}\n.bm-version-row .bm-restore {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex: none;\n min-height: 32px;\n padding: 0 10px;\n border-radius: 7px;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-version-rel {\n font-size: 14px;\n font-weight: 500;\n color: var(--bm-ink);\n}\n.bm-version-abs {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--bm-muted);\n}\n.bm-version-diff {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 4px 10px 12px 10px;\n border-top: 1px solid var(--bm-divider);\n margin-top: 0;\n}\n.bm-version-diff ul {\n margin: 0;\n}\n.bm-day {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.bm-restored {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 8px 8px 12px;\n border-radius: 9px;\n background: var(--bm-diff-add-bg);\n color: var(--bm-saved-fg);\n font-size: 13px;\n}\n.bm-restored > span {\n flex: 1;\n min-width: 0;\n}\n\n.bm-tabs {\n display: flex;\n gap: 0;\n padding: 0 12px;\n overflow-x: auto;\n border-bottom: 1px solid var(--bm-tab-rule);\n}\n.bm-tabs button {\n flex: 1 1 auto;\n height: 46px;\n padding: 0 6px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: oklch(0.48 0.01 255);\n font-size: 13px;\n font-weight: 400;\n}\n.bm-tabs button:hover {\n color: var(--ink);\n background: var(--fill-soft);\n}\n.bm-tabs button[aria-selected=\"true\"] {\n color: var(--ink);\n background: transparent;\n font-weight: 600;\n box-shadow: inset 0 -2px 0 var(--accent);\n}\n.bm-tabs button:focus-visible {\n outline-offset: -2px;\n}\n\n.bm-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 24px 24px 32px;\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n.bm-foot {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n padding: 12px 16px;\n border-top: 1px solid var(--line-soft);\n font-family: var(--mono);\n font-size: 10px;\n color: var(--muted);\n}\n.bm-foot span:first-child {\n flex: none;\n white-space: nowrap;\n}\n.bm-foot span:last-child {\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n/* Group header: mono 11/500, then a 1px rule. With a right-hand item the rule sits on the flex wrapper. */\n.bm-group {\n margin: 18px 0 0;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--bm-divider);\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--bm-section);\n}\n.bm-group:first-child {\n margin-top: 0;\n}\n.bm-stack-tight > .bm-group {\n margin-bottom: 10px;\n}\n.bm-meta {\n margin: 0;\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n}\n\n/* Fields */\n.bm-label {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--bm-label);\n}\n.bm-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-hint {\n font-size: 12px;\n line-height: 1.45;\n font-weight: 400;\n color: var(--muted);\n}\n.bm-label-text {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n}\n.bm-info {\n position: relative;\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n margin-left: 4px;\n}\n.bm-info-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n margin: -3px 0;\n border-radius: 999px;\n color: var(--bm-info);\n cursor: help;\n text-transform: none;\n letter-spacing: 0;\n}\n.bm-info-btn:hover,\n.bm-info-btn[aria-expanded=\"true\"] {\n color: var(--ink);\n}\n.bm-info-btn:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 1px;\n}\n.bm-tip {\n position: fixed;\n z-index: 2147483647;\n visibility: hidden;\n pointer-events: none;\n padding: 8px 10px;\n border-radius: 8px;\n box-sizing: border-box;\n background: var(--ink);\n color: oklch(0.98 0.003 250);\n font-family: var(--sans, inherit);\n font-size: 12px;\n line-height: 1.45;\n font-weight: 400;\n text-transform: none;\n letter-spacing: 0;\n text-align: left;\n white-space: normal;\n box-shadow: 0 6px 20px rgb(0 0 0 / 0.25);\n}\n.bm-tip-open {\n visibility: visible;\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo) :where(input:not([type=\"checkbox\"]):not([type=\"file\"]), select, textarea) {\n width: 100%;\n min-height: 40px;\n padding: 0 12px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n color: var(--ink);\n font-size: 14px;\n font-weight: 400;\n outline: none;\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo) textarea {\n padding: 8px 12px;\n min-height: 72px;\n line-height: 1.5;\n resize: vertical;\n}\n:is(.bm-sidebar, .bm-popover) select:not([size]) {\n appearance: none;\n padding-right: 32px;\n /* A caret made of gradients, not a `data:` image: a site's Content-Security-Policy can block those. */\n background-image: linear-gradient(45deg, transparent 50%, #777 50%), linear-gradient(135deg, #777 50%, transparent 50%);\n background-size: 6px 6px;\n background-repeat: no-repeat;\n background-position:\n right 17px center,\n right 12px center;\n}\n.bm-sidebar select[size],\n.bm-popover select[size] {\n padding: 4px;\n font-size: 12px;\n}\n.bm-sidebar select[size] option,\n.bm-sidebar select[size] optgroup,\n.bm-popover select[size] option,\n.bm-popover select[size] optgroup {\n padding: 3px 6px;\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo) :where(input:not([type=\"checkbox\"]):not([type=\"file\"]), select, textarea):focus {\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px var(--bm-primary-ring);\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo) :where(input[aria-label=\"Link URL\"], .bm-mono) {\n font-family: var(--mono);\n font-size: 13px;\n}\n.bm-prefix-wrap {\n display: flex;\n align-items: center;\n min-height: 40px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n overflow: hidden;\n}\n.bm-prefix-wrap:focus-within {\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px var(--bm-primary-ring);\n}\n.bm-prefix {\n padding: 0 2px 0 12px;\n font-family: var(--mono);\n font-size: 13px;\n color: var(--muted);\n}\n.bm-prefix-wrap input {\n border: 0;\n box-shadow: none !important;\n min-height: 38px;\n padding-left: 2px;\n font-family: var(--mono);\n font-size: 13px;\n}\n.bm-stack {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n.bm-stack-tight {\n gap: 8px;\n}\n.bm-groups {\n gap: 36px;\n}\n.bm-list {\n display: flex;\n flex-direction: column;\n border-radius: 10px;\n box-shadow: 0 0 0 1px var(--bm-border);\n overflow: hidden;\n}\n.bm-list-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px 8px 12px;\n border-bottom: 1px solid var(--line-soft);\n}\n.bm-list-row:last-child {\n border-bottom: 0;\n}\n.bm-list-row-on {\n background: var(--accent-tint);\n}\n.bm-list-row a {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n color: var(--ink);\n text-decoration: none;\n}\n.bm-list-row a:hover .bm-list-title {\n text-decoration: underline;\n}\n.bm-list-title {\n font-size: 14px;\n font-weight: 500;\n}\n.bm-list-path {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n}\n.bm-badge-home {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n background: var(--bm-badge-green-bg);\n color: var(--bm-badge-green-fg);\n}\n.bm-badge {\n font-family: var(--mono);\n font-size: 11px;\n padding: 3px 7px;\n border-radius: 5px;\n background: var(--bm-badge-amber-bg);\n color: var(--bm-badge-amber-fg);\n}\n.bm-badge-system {\n background: var(--fill);\n color: var(--ink-2);\n}\n.bm-badge-on {\n background: var(--bm-badge-green-bg);\n color: var(--bm-badge-green-fg);\n}\n.bm-row {\n display: flex;\n gap: 6px;\n align-items: center;\n flex-wrap: wrap;\n}\n.bm-row-split {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n}\n.bm-error {\n color: var(--danger-ink);\n font-size: 12px;\n font-weight: 400;\n margin: 0;\n}\n.bm-warn {\n color: var(--warn-ink);\n font-size: 12px;\n margin: 0;\n}\n.bm-note {\n margin: 0;\n color: var(--bm-help);\n font-size: 13px;\n line-height: 1.55;\n font-weight: 400;\n}\n.bm-group + .bm-note,\n.bm-group-split + .bm-note {\n margin-top: -4px;\n}\n\n/* Switch: 36 x 20, knob 16 inset 2 */\n.bm-check {\n flex-direction: row;\n align-items: center;\n gap: 10px;\n font-weight: 500;\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"] {\n appearance: none;\n position: relative;\n flex: none;\n width: 36px;\n height: 20px;\n margin: 0;\n border-radius: 999px;\n background: var(--bm-switch-off);\n cursor: pointer;\n transition: background 0.15s;\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"]::before {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: #fff;\n box-shadow: 0 1px 2px oklch(0 0 0 / 0.2);\n transition: transform 0.15s;\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"]:checked {\n background: var(--bm-primary);\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"]:checked::before {\n transform: translateX(16px);\n}\n.bm-popover .bm-check {\n color: var(--bm-label);\n font-size: 14px;\n}\n\n/* Buttons inside the sidebar */\n.bm-sidebar :where(button:not([role=\"tab\"]):not([role=\"radio\"]):not(.bm-resize)) {\n min-height: 32px;\n padding: 0 12px;\n border: 0;\n border-radius: 8px;\n background: var(--fill);\n color: var(--ink);\n font-size: 13px;\n font-weight: 500;\n}\n.bm-sidebar :where(button:not([role=\"tab\"]):not([role=\"radio\"]):not(.bm-resize)):hover:not(:disabled) {\n background: var(--fill-hover);\n}\n.bm-sidebar button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n/* Dashed \"Add ...\" buttons: Add link, Add button, Add column, Add item */\n.bm-sidebar .bm-add {\n min-height: 44px;\n background: oklch(0.985 0.002 250);\n color: var(--bm-link);\n border: 1px dashed oklch(0.85 0.005 250);\n border-radius: 8px;\n}\n.bm-sidebar .bm-add:hover:not(:disabled) {\n background: var(--accent-tint);\n}\n\n/* Cards, lists, images */\n.bm-card {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n}\n.bm-card .bm-card {\n background: var(--bm-fill-nested);\n border-color: var(--line-soft);\n}\n.bm-card > .bm-label:first-child:not(:only-child) {\n font-family: var(--mono);\n font-size: 11px;\n letter-spacing: 0.04em;\n font-weight: 500;\n color: var(--muted);\n}\n.bm-card[draggable=\"true\"] {\n cursor: grab;\n}\n/* Drag and drop: the target shows what a drop would do. */\n.bm-dragging {\n opacity: 0.4;\n}\n.bm-drop-before,\n.bm-drop-after,\n.bm-drop-child {\n --drop: var(--accent);\n}\n.bm-drop-before::before,\n.bm-drop-after::before {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n height: 3px;\n border-radius: 3px;\n background: var(--drop);\n box-shadow: 0 0 0 2px var(--accent-ring);\n pointer-events: none;\n z-index: 2;\n}\n.bm-drop-before::before {\n top: -6px;\n}\n.bm-drop-after::before {\n bottom: -6px;\n}\n.bm-drop-child {\n box-shadow: inset 0 0 0 2px var(--drop);\n background: var(--accent-tint);\n}\n.bm-drop-before::after,\n.bm-drop-after::after,\n.bm-drop-child::after,\n.bm-drop-files::after {\n content: attr(data-drop-hint);\n position: absolute;\n right: 8px;\n padding: 3px 8px;\n border-radius: 6px;\n background: var(--ink);\n color: #fff;\n font-size: 11px;\n font-weight: 500;\n line-height: 1.3;\n white-space: nowrap;\n pointer-events: none;\n z-index: 3;\n}\n.bm-drop-before::after {\n top: -22px;\n}\n.bm-drop-after::after {\n bottom: -22px;\n}\n.bm-drop-child::after {\n top: -11px;\n right: 12px;\n}\n.bm-drop-files {\n box-shadow: inset 0 0 0 2px var(--accent);\n background: var(--accent-tint);\n}\n.bm-drop-files::after {\n top: -11px;\n right: 12px;\n}\n.bm-thumb {\n width: 100%;\n height: 96px;\n object-fit: cover;\n border-radius: 7px;\n background: var(--fill);\n}\n.bm-drop {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px dashed var(--line);\n border-radius: 10px;\n padding: 10px;\n background: var(--fill-soft);\n}\n.bm-drop input[type=\"file\"] {\n width: 100%;\n font-size: 12px;\n color: var(--muted);\n}\n.bm-drop input[type=\"file\"]::file-selector-button {\n height: 32px;\n margin-right: 10px;\n padding: 0 12px;\n border: 0;\n border-radius: 7px;\n background: var(--ink);\n color: #fff;\n font: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n}\n.bm-alert {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 14px;\n border-radius: 12px;\n background: var(--danger-tint);\n box-shadow: 0 0 0 1px oklch(0.55 0.18 25 / 0.35);\n}\n.bm-alert-title {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--danger-ink);\n}\n.bm-alert .bm-error {\n font-family: var(--mono);\n font-size: 11px;\n}\n.bm-alert-notice {\n background: var(--warn-tint);\n box-shadow: 0 0 0 1px oklch(0.45 0.09 65 / 0.2);\n}\n.bm-alert-notice .bm-note {\n color: var(--warn-ink);\n font-size: 12px;\n}\n\n/* Header actions */\n.bm-save {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 34px;\n padding: 0 12px;\n border: 0;\n border-radius: 8px;\n background: var(--accent);\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n}\n.bm-dialog .bm-primary kbd {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n margin-left: 8px;\n opacity: 0.8;\n}\n.bm-save kbd {\n font-family: var(--mono);\n font-size: 10px;\n font-weight: 400;\n opacity: 0.75;\n}\n/* Icon buttons: 32 x 32, transparent, grey icon, grey fill on hover. */\n.bm-icon-btn {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: 32px;\n height: 32px;\n min-height: 0 !important;\n padding: 0 !important;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--bm-icon);\n}\n.bm-icon-btn:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n.bm-icon-btn:disabled {\n opacity: 0.35;\n}\n.bm-close {\n width: 32px;\n height: 32px;\n background: transparent;\n color: var(--bm-icon);\n border-radius: 7px;\n}\n.bm-close:hover:not(:disabled) {\n background: var(--fill) !important;\n color: var(--ink);\n}\n.bm-dock .bm-save {\n font-family: var(--sans);\n}\n.bm-split {\n position: relative;\n display: inline-flex;\n flex: none;\n}\n.bm-split .bm-split-main {\n border-radius: 8px 0 0 8px;\n}\n.bm-split .bm-split-toggle {\n width: 28px;\n padding: 0;\n justify-content: center;\n border-radius: 0 8px 8px 0;\n box-shadow: inset 1px 0 0 oklch(1 0 0 / 0.35);\n}\n.bm-split .bm-split-toggle:focus-visible,\n.bm-split .bm-split-main:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n.bm-split-menu {\n position: absolute;\n z-index: 8;\n top: calc(100% + 6px);\n right: 0;\n min-width: 200px;\n display: flex;\n flex-direction: column;\n padding: 4px;\n border-radius: 10px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-split-menu button.bm-split-item {\n display: flex;\n align-items: center;\n width: 100%;\n min-height: 34px;\n padding: 0 10px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--ink);\n font-family: var(--sans);\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n}\n.bm-split-menu button.bm-split-item:hover:not(:disabled),\n.bm-split-menu button.bm-split-item:focus-visible {\n background: var(--fill);\n outline: none;\n}\n.bm-split-menu button.bm-split-danger {\n color: var(--danger-ink);\n}\n.bm-split-menu button.bm-split-item {\n justify-content: space-between;\n gap: 16px;\n}\n.bm-split-menu button.bm-split-item kbd {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--muted);\n}\n.bm-split-menu button.bm-split-sep {\n margin-top: 5px;\n position: relative;\n}\n.bm-split-menu button.bm-split-sep::before {\n content: \"\";\n position: absolute;\n left: 6px;\n right: 6px;\n top: -3px;\n height: 1px;\n background: var(--line);\n}\n.bm-split-menu button.bm-split-danger:hover:not(:disabled),\n.bm-split-menu button.bm-split-danger:focus-visible {\n background: var(--danger-tint);\n}\n.bm-split-menu button.bm-split-item:disabled {\n opacity: 0.45;\n cursor: default;\n}\n.bm-sidebar .bm-icon-btn.bm-danger {\n color: var(--bm-danger-icon);\n}\n.bm-sidebar .bm-icon-btn.bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-small {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n min-height: 28px !important;\n padding: 0 10px !important;\n font-family: var(--sans);\n font-size: 12px !important;\n letter-spacing: 0;\n text-transform: none;\n align-self: flex-start;\n}\n.bm-group-split {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-top: 18px;\n margin-bottom: 0;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--bm-divider);\n}\n.bm-group-split:first-child {\n margin-top: 0;\n}\n.bm-group-split > .bm-group {\n margin: 0;\n padding: 0;\n border: 0;\n}\n.bm-group-split .bm-small {\n text-transform: none;\n letter-spacing: 0;\n}\n.bm-group-split span.bm-small {\n font-family: var(--mono);\n font-size: 11px !important;\n font-weight: 400;\n color: var(--bm-muted);\n padding: 0 !important;\n min-height: 0 !important;\n}\n.bm-stack-tight > .bm-group-split {\n margin-bottom: 10px;\n}\n\n/* Labels with a right-hand tag */\n.bm-label.bm-label-row,\n.bm-label-row {\n flex-direction: row;\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 8px;\n}\n.bm-meta-tag {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n letter-spacing: 0;\n color: var(--bm-muted);\n}\n\n/* Switch rows */\n.bm-switch-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n cursor: pointer;\n}\n.bm-switch-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n.bm-switch-title {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n font-weight: 500;\n color: var(--bm-label);\n}\n\n/* Tone cards and segmented controls */\n.bm-tones {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 6px;\n}\n:is(.bm-sidebar, .bm-popover) .bm-tone {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 6px;\n min-height: 0;\n padding: 5px 5px 6px;\n border-radius: 9px;\n background: #fff;\n border: 0;\n box-shadow: inset 0 0 0 1px var(--bm-border);\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n}\n:is(.bm-sidebar, .bm-popover) .bm-tone:hover {\n background: var(--fill-soft);\n}\n:is(.bm-sidebar, .bm-popover) .bm-tone[aria-checked=\"true\"] {\n box-shadow: inset 0 0 0 2px var(--accent);\n background: #fff;\n}\n.bm-tones-2 {\n grid-template-columns: repeat(2, 1fr);\n}\n.bm-tones-3 {\n grid-template-columns: repeat(3, 1fr);\n}\n/* A miniature of each button look, drawn with the editor's colours so it does not depend on the site theme. */\n.bm-btnsample {\n display: grid;\n place-items: center;\n height: 26px;\n border-radius: 6px;\n background: var(--fill-soft);\n}\n.bm-btnsample > span {\n display: block;\n font-size: 10px;\n font-weight: 600;\n line-height: 1;\n}\n.bm-btnsample-default > span {\n color: var(--ink-2);\n}\n.bm-btnsample-primary > span {\n padding: 5px 12px;\n border-radius: 999px;\n background: var(--accent);\n color: #fff;\n}\n.bm-btnsample-secondary > span {\n padding: 5px 12px;\n border-radius: 999px;\n color: var(--ink);\n box-shadow: inset 0 0 0 1px var(--ink-2);\n}\n.bm-btnsample-tertiary > span {\n color: var(--accent);\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n.bm-swatch {\n display: inline-block;\n flex: none;\n width: 10px;\n height: 10px;\n border-radius: 3px;\n box-shadow: inset 0 0 0 1px oklch(0.2 0.02 255 / 0.15);\n}\n.bm-swatch-lg {\n display: block;\n width: auto;\n height: 22px;\n border-radius: 6px;\n}\n.bm-swatch-base {\n background: #fff;\n}\n.bm-swatch-subtle {\n background: oklch(0.96 0.005 250);\n}\n.bm-swatch-inverse {\n background: var(--ink);\n}\n.bm-swatch-brand {\n background: var(--accent);\n}\n.bm-segmented {\n display: flex;\n padding: 3px;\n border-radius: 9px;\n background: var(--bm-fill);\n}\n.bm-sidebar .bm-segmented button,\n.bm-dialog .bm-segmented button {\n flex: 1;\n min-height: 36px;\n height: 36px;\n padding: 0 8px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: oklch(0.45 0.01 255);\n font-size: 13px;\n font-weight: 400;\n}\n.bm-sidebar .bm-segmented button:hover:not(:disabled),\n.bm-dialog .bm-segmented button:hover:not(:disabled) {\n background: oklch(1 0 0 / 0.5);\n}\n.bm-sidebar .bm-segmented button[aria-checked=\"true\"],\n.bm-dialog .bm-segmented button[aria-checked=\"true\"] {\n background: #fff;\n color: var(--ink);\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-icon-picker {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));\n gap: 4px;\n padding: 3px;\n border-radius: 9px;\n background: var(--bm-fill);\n}\n.bm-sidebar .bm-icon-picker button {\n display: grid;\n place-items: center;\n min-height: 40px;\n height: 40px;\n padding: 0;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: oklch(0.45 0.01 255);\n}\n.bm-sidebar .bm-icon-picker button:hover {\n background: oklch(1 0 0 / 0.5);\n color: var(--ink);\n}\n.bm-sidebar .bm-icon-picker button[aria-checked=\"true\"] {\n background: #fff;\n color: var(--accent);\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-icon-picker svg {\n width: 20px;\n height: 20px;\n}\n.bm-actions-split {\n display: flex;\n gap: 8px;\n padding-top: 4px;\n}\n.bm-actions-split button {\n flex: 1;\n min-height: 40px !important;\n font-size: 14px !important;\n}\n.bm-sidebar .bm-actions-split .bm-danger {\n background: var(--bm-danger-soft);\n}\n\n/* Arrays, links, images */\n.bm-array {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-array-item {\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n overflow: hidden;\n}\n.bm-array-item summary {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 0 8px 0 10px;\n font-size: 14px;\n font-weight: 500;\n color: var(--ink);\n cursor: pointer;\n list-style: none;\n}\n.bm-array-item summary::-webkit-details-marker {\n display: none;\n}\n.bm-array-item summary:hover {\n background: var(--fill-soft);\n}\n.bm-array-summary {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-grip,\n.bm-chevron {\n display: inline-grid;\n place-items: center;\n color: oklch(0.65 0.01 255);\n}\n.bm-chevron {\n transition: transform 0.12s;\n}\ndetails[open] > summary .bm-chevron {\n transform: rotate(90deg);\n}\n.bm-array-body {\n display: flex;\n flex-direction: column;\n gap: 18px;\n padding: 12px;\n background: var(--bm-fill-nested);\n border-top: 1px solid var(--line-soft);\n}\n.bm-row-end {\n justify-content: flex-end;\n}\n.bm-sidebar .bm-add-row {\n width: 100%;\n}\n.bm-link-btn {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n min-height: 40px;\n padding: 0 12px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n text-align: left;\n color: var(--ink-2);\n}\n.bm-sidebar .bm-link-btn {\n background: #fff;\n border: 1px solid var(--bm-border);\n font-size: 14px;\n padding: 0 12px;\n}\n.bm-sidebar .bm-link-btn:hover:not(:disabled) {\n background: #fff;\n border-color: oklch(0.8 0.005 250);\n}\n.bm-link-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--ink);\n font-weight: 500;\n}\n.bm-link-href {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n max-width: 45%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-stripes {\n background: repeating-linear-gradient(135deg, oklch(0.93 0.004 250) 0 6px, oklch(0.965 0.003 250) 6px 12px);\n}\n\n/* Image field: label above, compact 56px row, alt text under it */\n.bm-imagefield {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-image-row {\n display: flex;\n gap: 10px;\n align-items: center;\n}\n.bm-image-row .bm-thumb {\n flex: none;\n width: 56px;\n height: 56px;\n border-radius: 6px;\n}\n.bm-image-meta {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n justify-content: center;\n}\n.bm-image-path {\n font-family: var(--mono);\n font-size: 12px;\n color: var(--bm-label);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-sidebar .bm-alt {\n min-height: 40px;\n font-size: 14px;\n}\n.bm-image-actions {\n flex-wrap: nowrap;\n gap: 6px;\n}\n.bm-image-actions > button:not(.bm-icon-btn) {\n flex: 1;\n min-height: 36px;\n font-size: 13px;\n}\n.bm-layout {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 2px;\n}\n.bm-layout-row {\n display: grid;\n grid-template-columns: 56px 1fr;\n align-items: center;\n column-gap: 10px;\n row-gap: 4px;\n}\n.bm-layout-row .bm-label {\n margin: 0;\n}\n.bm-layout-row .bm-layout-hint {\n grid-column: 2;\n}\n.bm-position {\n display: grid;\n grid-template-columns: repeat(3, 20px);\n grid-template-rows: repeat(3, 20px);\n gap: 3px;\n padding: 4px;\n width: max-content;\n border-radius: 8px;\n background: var(--fill);\n}\n.bm-sidebar .bm-position-cell {\n width: 20px;\n height: 20px;\n min-height: 0;\n padding: 0;\n border: 0;\n border-radius: 5px;\n background: #fff;\n box-shadow: inset 0 0 0 1px var(--line);\n}\n.bm-sidebar .bm-position-cell:hover:not(:disabled) {\n background: var(--accent-tint);\n}\n.bm-sidebar .bm-position-cell[aria-checked=\"true\"],\n.bm-sidebar .bm-position-cell[aria-checked=\"true\"]:hover:not(:disabled) {\n background: var(--accent);\n box-shadow: none;\n}\n.bm-sidebar .bm-position-cell:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.bm-slot,\n.bm-dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n width: 100%;\n min-height: 96px;\n padding: 14px;\n border: 1.5px dashed oklch(0.82 0.006 250);\n border-radius: 10px;\n background: var(--fill-soft);\n color: var(--ink-2);\n text-align: center;\n cursor: pointer;\n}\n.bm-sidebar .bm-slot:hover:not(:disabled),\n.bm-dropzone:hover {\n border-color: var(--accent);\n background: var(--accent-tint);\n}\n.bm-dropzone {\n min-height: 180px;\n position: relative;\n}\n.bm-dropzone:focus-within {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n.bm-dropzone-over {\n border-color: var(--accent);\n background: var(--accent-tint);\n}\n.bm-slot-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--ink);\n}\n.bm-slot-hint {\n font-size: 11px;\n color: var(--muted);\n}\n.bm-scrim {\n position: fixed;\n inset: 0;\n z-index: 7;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding: 10vh 16px 16px;\n background: oklch(0.2 0.01 255 / 0.4);\n}\n.bm-modal {\n display: flex;\n flex-direction: column;\n width: min(480px, 100%);\n max-height: min(560px, 80vh);\n overflow: hidden;\n padding: 20px 0 0;\n border-radius: 14px;\n background: #fff;\n box-shadow: var(--bm-shadow-dialog);\n}\n.bm-modal-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 0 20px 12px;\n}\n.bm-modal-head .bm-dialog-title {\n flex: none;\n}\n.bm-modal-head .bm-meta-tag {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-modal-head .bm-icon-btn {\n margin: -6px -8px -6px 0;\n}\n.bm-modal .bm-tabs {\n margin: 0 20px;\n padding: 3px;\n gap: 0;\n border: 0;\n border-radius: 9px;\n background: var(--bm-fill);\n overflow: visible;\n}\n.bm-modal .bm-tabs button {\n flex: 1;\n height: 36px;\n min-height: 36px;\n padding: 0 8px;\n border-radius: 7px;\n font-size: 13px;\n font-weight: 400;\n}\n.bm-modal .bm-tabs button:hover {\n background: oklch(1 0 0 / 0.5);\n}\n.bm-modal .bm-tabs button[aria-selected=\"true\"] {\n background: #fff;\n color: var(--ink);\n font-weight: 500;\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-modal-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 16px 20px 20px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.bm-library {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 10px;\n}\n.bm-library-item {\n position: relative;\n}\n.bm-library-pick {\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n min-height: 0;\n padding: 4px;\n border: 0;\n border-radius: 9px;\n background: var(--fill-soft);\n text-align: left;\n font-family: var(--mono);\n font-size: 9px;\n font-weight: 400;\n color: var(--muted);\n word-break: break-all;\n cursor: pointer;\n}\n.bm-library-pick:hover {\n background: var(--fill-hover);\n}\n.bm-library-pick img {\n width: 100%;\n aspect-ratio: 1 / 1;\n object-fit: cover;\n border-radius: 6px;\n background: var(--fill);\n}\n.bm-library-pick[aria-pressed=\"true\"] {\n box-shadow: 0 0 0 2px var(--accent);\n background: var(--accent-tint);\n}\n.bm-library-delete {\n position: absolute;\n top: 8px;\n right: 8px;\n width: 24px;\n height: 24px;\n min-height: 0;\n background: #fff;\n box-shadow: 0 1px 3px oklch(0.2 0.01 255 / 0.25);\n opacity: 0;\n}\n.bm-library-item:hover .bm-library-delete,\n.bm-library-delete:focus-visible {\n opacity: 1;\n}\n.bm-library-empty {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n}\n.bm-modal-confirm {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px 20px 16px;\n border-top: 1px solid var(--line-soft);\n background: var(--danger-tint);\n}\n.bm-modal-confirm .bm-note {\n color: var(--danger-ink);\n font-size: 13px;\n line-height: 1.5;\n}\n.bm-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n border: 0;\n white-space: nowrap;\n}\n.bm-popover-title {\n grid-column: 1 / -1;\n padding: 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--bm-ink);\n}\n.bm-popover-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0;\n}\n.bm-popover-head-wide {\n grid-column: 1 / -1;\n}\n.bm-popover[aria-label=\"Edit link\"],\n.bm-popover[aria-label=\"Add section\"][role=\"listbox\"] {\n z-index: 5;\n}\n.bm-popover :is(.bm-fmt-bold) {\n font-weight: 700;\n}\n.bm-fmt-bold {\n font-weight: 700;\n font-size: 13px;\n}\n.bm-fmt-italic {\n font-family: var(--serif);\n font-style: italic;\n font-size: 15px;\n}\n\n/* Edit link: Advanced row */\n.bm-advanced {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n.bm-popover button.bm-advanced-toggle {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-height: 32px;\n padding: 0 2px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--bm-label);\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n}\n.bm-popover button.bm-advanced-toggle:hover {\n background: transparent;\n color: var(--bm-ink);\n}\n.bm-advanced-toggle .bm-chevron {\n transition: transform 0.12s;\n}\n.bm-advanced-toggle[aria-expanded=\"true\"] .bm-chevron {\n transform: rotate(90deg);\n}\n.bm-advanced-summary {\n margin-left: auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--bm-muted);\n}\n\n/* SEO card and dialog */\n.bm-seo-card {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.bm-seo-badges {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.bm-seo-badge {\n padding: 2px 8px;\n border-radius: 999px;\n background: var(--fill-soft);\n color: var(--bm-label);\n font-family: var(--mono);\n font-size: 11px;\n}\n.bm-seo-edit {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n.bm-dialog.bm-seo {\n position: relative;\n width: min(560px, 100%);\n max-height: calc(100vh - 10vh - 32px);\n min-height: 0;\n}\n.bm-seo-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n min-height: 0;\n overflow-y: auto;\n padding: 2px 4px 2px 2px;\n}\n.bm-seo-json {\n min-height: 220px;\n white-space: pre;\n overflow: auto;\n tab-size: 2;\n}\n.bm-seo-json[aria-invalid=\"true\"] {\n border-color: var(--bm-danger);\n}\n.bm-seo-format {\n align-self: flex-start;\n}\n\n/* SEO preview, OG row, outline */\n.bm-serp {\n display: flex;\n flex-direction: column;\n gap: 3px;\n padding: 12px 14px;\n border-radius: 10px;\n background: var(--fill-soft);\n}\n.bm-serp-image {\n flex-direction: row;\n align-items: flex-start;\n gap: 12px;\n}\n.bm-serp-text {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n.bm-serp-thumb {\n flex: none;\n width: 64px;\n height: 64px;\n border-radius: 8px;\n object-fit: cover;\n background: var(--fill);\n}\n.bm-serp-title {\n font-size: 15px;\n font-weight: 500;\n color: oklch(0.42 0.12 260);\n}\n.bm-serp-url {\n font-family: var(--mono);\n font-size: 11px;\n color: oklch(0.45 0.08 145);\n}\n.bm-serp-desc {\n font-size: 12px;\n line-height: 1.45;\n color: oklch(0.45 0.01 255);\n}\n.bm-outline-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.bm-sidebar .bm-outline-row {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n min-height: 40px;\n padding: 0 10px;\n border-radius: 8px;\n background: transparent;\n text-align: left;\n font-size: 14px;\n}\n.bm-sidebar .bm-outline-row:hover:not(:disabled) {\n background: var(--fill-soft);\n}\n\n/* Section rows (Pages tab): grip, tone swatch, name over #anchor and variant, then actions. */\n.bm-srow {\n position: relative;\n display: flex;\n align-items: center;\n gap: 4px;\n min-height: 52px;\n padding: 6px 6px 6px 8px;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n}\n.bm-srow:hover {\n border-color: oklch(0.8 0.008 250);\n}\n.bm-srow-grip {\n flex: none;\n width: 16px;\n height: 32px;\n display: inline-grid;\n place-items: center;\n cursor: grab;\n touch-action: none;\n}\n.bm-srow-grip:active {\n cursor: grabbing;\n}\n.bm-srow .bm-outline-row {\n flex: 1;\n min-width: 0;\n width: auto;\n padding: 0 8px 0 4px;\n gap: 10px;\n}\n.bm-srow .bm-swatch {\n width: 10px;\n height: 10px;\n border-radius: 2px;\n}\n.bm-srow-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n.bm-srow-name {\n font-size: 14px;\n font-weight: 500;\n color: var(--bm-ink);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-srow-meta {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--bm-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-srow .bm-outline-meta {\n flex: none;\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-srow-btn {\n width: 32px;\n height: 32px;\n background: transparent;\n color: var(--bm-icon);\n border-radius: 7px;\n}\n.bm-srow-btn:disabled {\n opacity: 0.35;\n}\n.bm-sidebar .bm-srow-btn:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n.bm-sidebar .bm-srow-btn.bm-danger {\n color: var(--bm-danger-icon);\n}\n.bm-sidebar .bm-srow-btn.bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n}\n.bm-srow-sep {\n flex: none;\n width: 1px;\n height: 20px;\n margin: 0 2px;\n background: var(--bm-divider);\n}\n.bm-outline-n {\n width: 18px;\n font-family: var(--mono);\n font-size: 11px;\n color: oklch(0.55 0.01 255);\n}\n.bm-outline-label {\n flex: 1;\n min-width: 0;\n font-weight: 500;\n}\n.bm-outline-meta {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--muted);\n}\n\n/* Navigation and footer link cards */\n.bm-nav-card {\n padding: 12px 12px 14px;\n gap: 10px;\n}\n.bm-nested {\n margin: 6px 0 0 16px;\n}\n.bm-nav-children {\n margin-top: -4px;\n}\n.bm-nav-head {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.bm-nav-head .bm-icon-btn,\n.bm-column-head .bm-icon-btn {\n background: var(--bm-fill);\n color: oklch(0.45 0.01 255);\n}\n.bm-nav-head .bm-icon-btn:hover:not(:disabled),\n.bm-column-head .bm-icon-btn:hover:not(:disabled) {\n background: var(--bm-fill-hover);\n color: var(--bm-ink);\n}\n.bm-sidebar .bm-nav-head .bm-icon-btn.bm-danger,\n.bm-sidebar .bm-column-head .bm-icon-btn.bm-danger {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-sidebar .bm-nav-label {\n flex: 1;\n min-width: 0;\n min-height: 32px;\n padding: 0 8px;\n border-color: transparent;\n font-weight: 500;\n}\n.bm-sidebar .bm-nav-label:hover {\n border-color: var(--line);\n}\n.bm-column {\n padding: 0;\n gap: 0;\n}\n.bm-column-head {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px;\n cursor: grab;\n}\n.bm-column-links > summary {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: 40px;\n padding: 0 12px;\n border-top: 1px solid var(--line-soft);\n font-size: 13px;\n font-weight: 500;\n color: var(--bm-label);\n cursor: pointer;\n list-style: none;\n}\n.bm-column-links > summary::-webkit-details-marker {\n display: none;\n}\n.bm-column-links > :not(summary) {\n margin: 10px 12px 0;\n}\n.bm-column-links > :last-child {\n margin-bottom: 12px;\n}\n\n/* Wordmark preview */\n.bm-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.bm-card-head .bm-label {\n flex: none;\n}\n.bm-combo {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n:is(.bm-sidebar, .bm-popover) .bm-combo-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n width: auto;\n max-width: 140px;\n min-height: 38px;\n padding: 0 10px 0 12px;\n border: 0;\n border-left: 1px solid var(--bm-border);\n border-radius: 0;\n background: var(--fill-soft);\n color: var(--ink-2);\n font-family: var(--mono);\n font-size: 12px;\n font-weight: 400;\n text-align: left;\n}\n:is(.bm-sidebar, .bm-popover) .bm-combo-trigger:hover:not(:disabled) {\n background: var(--fill-hover);\n}\n:is(.bm-sidebar, .bm-popover) .bm-combo-trigger[aria-expanded=\"true\"] {\n background: var(--accent-tint);\n color: var(--accent-hover);\n}\n/* One URL field: the text input and the page picker share a single border. */\n.bm-linkfield {\n display: flex;\n align-items: stretch;\n min-height: 40px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n overflow: hidden;\n}\n.bm-linkfield:focus-within {\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px var(--bm-primary-ring);\n}\n.bm-linkfield > input {\n flex: 1;\n min-width: 0;\n border: 0 !important;\n box-shadow: none !important;\n border-radius: 0;\n min-height: 38px;\n background: transparent;\n}\n.bm-linkfield .bm-combo {\n flex: none;\n max-width: 45%;\n}\n.bm-linkfield .bm-combo-trigger {\n height: 100%;\n}\n.bm-linkfield .bm-combo-trigger:focus-visible {\n outline-offset: -2px;\n}\n.bm-combo-trigger > span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-combo-trigger .bm-combo-custom {\n color: var(--muted);\n}\n.bm-combo-panel {\n position: fixed;\n z-index: 6;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n box-shadow: 0 6px 18px oklch(0.2 0.02 255 / 0.1);\n}\n.bm-combo-list {\n max-height: 200px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n}\n.bm-combo-group {\n margin: 6px 6px 2px;\n font-family: var(--mono);\n font-size: 10px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--muted);\n}\n.bm-combo-option {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 10px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 13px;\n color: var(--ink);\n cursor: pointer;\n}\n.bm-combo-option[aria-selected=\"true\"] {\n font-weight: 600;\n color: var(--accent-hover);\n}\n.bm-combo-active {\n background: var(--fill);\n}\n.bm-combo-value {\n flex: none;\n max-width: 50%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n}\n.bm-combo-empty {\n margin: 0;\n padding: 8px;\n font-size: 12px;\n color: var(--muted);\n}\n.bm-format {\n margin-top: -4px;\n}\n.bm-sidebar .bm-format button[aria-pressed=\"true\"] {\n background: #fff;\n color: var(--ink);\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-wordmark {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n padding: 12px 14px;\n border-radius: 10px;\n background: var(--bm-fill-soft);\n}\n.bm-wordmark-name {\n font-size: 24px;\n font-weight: 600;\n letter-spacing: -0.03em;\n}\n.bm-alert-notice {\n flex-direction: row;\n align-items: flex-start;\n gap: 8px;\n color: var(--warn-ink);\n}\n.bm-alert-notice .bm-icon {\n margin-top: 2px;\n flex: none;\n}\n\n/*\n * Button system. Three variants, one danger modifier, one rule set.\n * secondary (default): neutral fill, ink text.\n * .bm-primary: the one main action of a surface. Solid accent, white text (AA).\n * .bm-tertiary: low emphasis text button (Cancel, Reset). No fill, no underline, grey fill on hover.\n * .bm-danger: modifier. primary = solid red, secondary = red text, tertiary = red text.\n * The scope list gives every rule enough specificity to beat the per-surface defaults above,\n * so the hover state of one variant can never fall back to the secondary fill.\n */\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button:where(.bm-primary, .bm-tertiary, .bm-danger):not(.bm-icon-btn, .bm-save) {\n transition:\n background-color 0.12s,\n color 0.12s;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary {\n background: var(--bm-primary);\n color: #fff;\n box-shadow: none;\n font-weight: 600;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary:hover:not(:disabled) {\n background: var(--bm-primary-hover);\n color: #fff;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary.bm-danger {\n background: var(--bm-danger);\n color: #fff;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary.bm-danger:hover:not(:disabled) {\n background: var(--danger-hover);\n color: #fff;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-danger:not(.bm-primary, .bm-tertiary, .bm-icon-btn) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-danger:not(.bm-primary, .bm-tertiary, .bm-icon-btn):hover:not(:disabled) {\n background: oklch(0.93 0.04 25);\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary {\n min-height: 32px;\n padding: 0 10px;\n border-radius: 8px;\n background: transparent;\n color: var(--bm-label);\n font-weight: 400;\n box-shadow: none;\n text-decoration: none;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal) button.bm-tertiary {\n min-height: 38px;\n font-size: 14px;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary.bm-danger {\n background: transparent;\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary.bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button:disabled {\n opacity: 0.5;\n cursor: default;\n}\n.bm-save:hover:not(:disabled) {\n background: var(--accent-hover);\n color: #fff;\n}\n.bm-sidebar .bm-save:hover:not(:disabled) {\n background: var(--accent-hover);\n color: #fff;\n}\n.bm-popover .bm-actions-remove,\n.bm-dialog .bm-actions-remove {\n margin-right: auto;\n}\n.bm-modal :where(button:not([role=\"tab\"], .bm-library-pick, .bm-icon-btn, .bm-tertiary)) {\n min-height: 38px;\n padding: 0 16px;\n border: 0;\n border-radius: 8px;\n background: var(--fill);\n color: var(--ink);\n font-size: 14px;\n font-weight: 400;\n}\n.bm-modal :where(button:not([role=\"tab\"], .bm-library-pick, .bm-icon-btn, .bm-tertiary)):hover:not(:disabled) {\n background: var(--fill-hover);\n}\n.bm-modal .bm-dropzone {\n font-family: var(--sans);\n}\n\n/* Design tab */\n.bm-colorrow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.bm-colorpick {\n flex: none;\n width: 40px !important;\n height: 40px;\n min-height: 40px !important;\n padding: 2px !important;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n cursor: pointer;\n}\n.bm-colorhex {\n flex: 1;\n min-width: 0;\n font-family: var(--mono);\n font-size: 13px;\n text-transform: lowercase;\n}\n.bm-colorhex[aria-invalid=\"true\"] {\n border-color: var(--bm-danger);\n}\n.bm-overrides {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n overflow: hidden;\n}\n.bm-override-row {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px 8px 12px;\n}\n.bm-override-row + .bm-override-row {\n border-top: 1px solid var(--bm-divider);\n}\n.bm-override-label {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: 6px;\n font-size: 13px;\n font-weight: 500;\n color: var(--bm-label);\n}\n.bm-override-label .bm-meta-tag {\n font-size: 10px;\n}\n.bm-override-row .bm-colorpick {\n width: 32px !important;\n height: 32px;\n min-height: 32px !important;\n padding: 1px !important;\n border-radius: 7px;\n}\n.bm-override-row .bm-colorhex {\n flex: none;\n width: 104px;\n min-height: 36px;\n padding: 0 10px;\n}\n.bm-tone-matrix {\n display: grid;\n grid-template-columns: 60px minmax(0, 1fr) minmax(0, 1fr);\n gap: 8px;\n align-items: stretch;\n}\n.bm-tone-pick {\n border: 0;\n text-align: left;\n font: inherit;\n cursor: pointer;\n}\n.bm-tone-cell[aria-pressed=\"true\"] {\n outline: 2px solid var(--bm-primary);\n outline-offset: 0;\n}\n.bm-tone-head {\n font-family: var(--mono);\n font-size: 10px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--muted);\n}\n.bm-tone-name {\n align-self: center;\n font-size: 12px;\n font-weight: 500;\n color: var(--ink-2);\n}\n.bm-tone-cell {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n min-width: 0;\n min-height: 46px;\n padding: 0 10px;\n border-radius: 8px;\n overflow: hidden;\n white-space: nowrap;\n}\n.bm-tone-aa {\n flex: none;\n font-size: 16px;\n font-weight: 600;\n}\n.bm-tone-muted {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 11px;\n}\n.bm-tone-chip {\n flex: none;\n padding: 2px 6px;\n border-radius: 5px;\n font-size: 10px;\n font-weight: 600;\n}\n.bm-tone-link {\n flex: none;\n font-size: 11px;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.bm-contrast-list {\n margin: 6px 0 0;\n padding-left: 16px;\n font-family: var(--mono);\n font-size: 11px;\n color: var(--warn-ink);\n}\n.bm-range {\n flex: 1;\n min-width: 0;\n min-height: 28px;\n accent-color: var(--accent);\n cursor: pointer;\n}\n/* Preview: the only editor UI left on screen. */\n.bm-exit-preview {\n position: fixed;\n z-index: 7;\n right: 16px;\n bottom: 16px;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 40px;\n padding: 0 16px;\n border: 0;\n border-radius: 999px;\n background: var(--ink);\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n box-shadow: 0 10px 30px oklch(0.2 0.02 255 / 0.3);\n}\n.bm-exit-preview:hover {\n background: oklch(0.28 0.012 255);\n}\n.bm-exit-preview:focus-visible {\n outline-color: oklch(0.82 0.14 145);\n outline-offset: 3px;\n}\n.bm-srow-add {\n display: flex;\n justify-content: flex-end;\n padding-top: 6px;\n}\n.bm-sidebar .bm-add-section {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 32px;\n padding: 0 12px;\n border: 0;\n border-radius: 8px;\n background: var(--bm-primary);\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-sidebar .bm-add-section:hover {\n background: var(--bm-primary-hover);\n}\n";
19968
+ var editor_default = "/*\n * Editor styles. They live in a shadow root, so they never meet the site's Tailwind layer.\n * The editor is always light. Tokens and values follow the v4 editor design handoff.\n * The short names (--ink, --line, --accent ...) alias the --bm-* tokens so older rules read the same.\n */\n:host {\n all: initial;\n\n /* ---------- v4 tokens (editor-tokens.css) ---------- */\n --bm-font-ui: \"Bricolage Grotesque Variable\", \"Bricolage Grotesque\", ui-sans-serif, system-ui, sans-serif;\n --bm-font-mono: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, monospace;\n --bm-font-serif: \"Instrument Serif\", Georgia, serif;\n\n --bm-ink: oklch(0.21 0.012 255);\n --bm-label: oklch(0.3 0.01 255);\n --bm-section: oklch(0.42 0.01 255);\n --bm-help: oklch(0.47 0.01 255);\n --bm-muted: oklch(0.5 0.01 255);\n --bm-icon: oklch(0.55 0.01 255);\n --bm-info: oklch(0.6 0.01 255);\n\n --bm-fill: oklch(0.955 0.003 250);\n --bm-fill-hover: oklch(0.93 0.004 250);\n --bm-fill-soft: oklch(0.965 0.003 250);\n --bm-fill-nested: oklch(0.97 0.003 250);\n --bm-border: oklch(0.88 0.005 250);\n --bm-divider: oklch(0.93 0.004 250);\n --bm-tab-rule: oklch(0.92 0.004 250);\n\n --bm-primary: oklch(0.46 0.13 145);\n --bm-primary-hover: oklch(0.4 0.12 145);\n --bm-primary-ring: oklch(0.46 0.13 145 / 0.15);\n --bm-link: oklch(0.4 0.12 145);\n\n --bm-saved-bg: oklch(0.94 0.045 145);\n --bm-saved-fg: oklch(0.36 0.1 145);\n --bm-unsaved-bg: oklch(0.95 0.05 80);\n --bm-unsaved-fg: oklch(0.48 0.1 60);\n --bm-unsaved-dot: oklch(0.75 0.15 70);\n --bm-badge-green-bg: oklch(0.93 0.06 145);\n --bm-badge-green-fg: oklch(0.38 0.1 145);\n --bm-badge-amber-bg: oklch(0.95 0.04 75);\n --bm-badge-amber-fg: oklch(0.45 0.09 60);\n\n --bm-danger: oklch(0.55 0.19 25);\n --bm-danger-text: oklch(0.52 0.17 25);\n --bm-danger-icon: oklch(0.58 0.18 25);\n --bm-danger-soft: oklch(0.96 0.025 20);\n\n --bm-diff-del-bg: oklch(0.97 0.02 20);\n --bm-diff-del-fg: oklch(0.45 0.13 25);\n --bm-diff-add-bg: oklch(0.96 0.04 145);\n --bm-diff-add-fg: oklch(0.34 0.1 145);\n\n --bm-switch-off: oklch(0.82 0.005 250);\n\n --bm-shadow-pop: 0 0 0 1px oklch(0.9 0.005 250), 0 16px 36px -16px oklch(0.2 0.02 255 / 0.35);\n --bm-shadow-dialog: 0 0 0 1px oklch(0.9 0.005 250), 0 24px 48px -24px oklch(0.2 0.02 255 / 0.35);\n --bm-shadow-segment-on: 0 1px 2px oklch(0 0 0 / 0.08), 0 0 0 1px oklch(0.9 0.005 250);\n\n /* ---------- aliases used by the rules below ---------- */\n --ink: var(--bm-ink);\n --ink-2: var(--bm-label);\n --muted: var(--bm-muted);\n --line: var(--bm-border);\n --line-soft: var(--bm-divider);\n --fill: var(--bm-fill);\n --fill-hover: var(--bm-fill-hover);\n --fill-soft: var(--bm-fill-soft);\n --accent: var(--bm-primary);\n --accent-hover: var(--bm-primary-hover);\n --accent-tint: oklch(0.96 0.03 145);\n --accent-ring: var(--bm-primary-ring);\n --warn-tint: var(--bm-unsaved-bg);\n --warn-ink: var(--bm-unsaved-fg);\n --warn-dot: var(--bm-unsaved-dot);\n --danger-hover: oklch(0.48 0.18 25);\n --danger-tint: var(--bm-danger-soft);\n --danger-ink: var(--bm-danger-text);\n --info-dot: oklch(0.6 0.15 255);\n --sans: var(--bm-font-ui);\n --mono: var(--bm-font-mono);\n --serif: var(--bm-font-serif);\n --shadow-pop: var(--bm-shadow-pop);\n}\n* {\n box-sizing: border-box;\n}\nbutton,\ninput,\nselect,\ntextarea {\n font: inherit;\n color: inherit;\n}\nbutton {\n cursor: pointer;\n}\n:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n\n/* On-page outlines */\n.bm-outline {\n position: fixed;\n pointer-events: none;\n border-radius: 6px;\n z-index: 1;\n}\n.bm-outline-section {\n border: 2px solid var(--accent);\n}\n.bm-outline-field {\n border: 2px solid var(--accent);\n background: oklch(0.46 0.13 145 / 0.08);\n}\n.bm-image-bar {\n flex-wrap: nowrap;\n left: auto;\n white-space: nowrap;\n}\n.bm-image-bar-group {\n display: flex;\n gap: 2px;\n}\n.bm-image-bar button[aria-pressed=\"true\"] {\n background: var(--bm-saved-bg);\n color: var(--bm-saved-fg);\n}\n.bm-image-bar-grid {\n display: grid;\n grid-template-columns: repeat(3, 9px);\n grid-template-rows: repeat(3, 9px);\n gap: 2px;\n align-self: center;\n padding: 0 4px;\n}\n.bm-image-bar .bm-pos-cell {\n width: 9px;\n height: 9px;\n /* `.bm-rich button` sets a 32px minimum for the bar's text buttons; the cells stay 9px. */\n min-width: 0;\n min-height: 0;\n padding: 0;\n border-radius: 2px;\n background: var(--line);\n}\n.bm-image-bar .bm-pos-cell:hover:not(:disabled) {\n background: var(--muted);\n}\n.bm-image-bar .bm-pos-cell[aria-pressed=\"true\"] {\n background: var(--accent);\n}\n.bm-image-bar .bm-pos-cell:disabled {\n opacity: 0.3;\n cursor: default;\n}\n.bm-outline-image {\n background: oklch(0.46 0.13 145 / 0.12);\n}\n.bm-outline-image::after {\n content: \"Change image\";\n position: absolute;\n top: 8px;\n left: 8px;\n padding: 4px 9px;\n border-radius: 6px;\n background: var(--accent);\n color: #fff;\n font: 500 11px / 1.3 var(--sans, system-ui, sans-serif);\n}\n\n.bm-toolbar,\n.bm-dock,\n.bm-exit-preview,\n.bm-sidebar,\n.bm-popover,\n.bm-dialog,\n.bm-rich,\n.bm-banner,\n.bm-scrim {\n pointer-events: auto;\n font-family: var(--sans);\n font-size: 13px;\n color: var(--ink);\n -webkit-font-smoothing: antialiased;\n}\n\n/*\n * Insert between sections. Three states:\n * idle / hover a solid line and a 28px circle; hover changes nothing.\n * open the picker is open: the line stays and a \"between A and B\" chip replaces the circle.\n */\n.bm-gap {\n position: fixed;\n z-index: 2;\n height: 0;\n pointer-events: none;\n}\n.bm-gap::before {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n height: 0;\n border-top: 2px solid var(--bm-primary);\n transform: translateY(-50%);\n}\n.bm-gap-add {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 999px;\n pointer-events: auto;\n cursor: pointer;\n white-space: nowrap;\n background: var(--bm-primary);\n color: #fff;\n box-shadow: 0 0 0 2px #fff;\n}\n.bm-gap-add .bm-icon {\n width: 14px;\n height: 14px;\n stroke-width: 2.4;\n}\n.bm-gap-add:focus-visible {\n outline: 2px solid var(--ink);\n outline-offset: 3px;\n}\n.bm-gap-chip {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n padding: 4px 10px;\n border-radius: 999px;\n background: #fff;\n color: var(--bm-ink);\n box-shadow: 0 0 0 1.5px var(--bm-primary);\n white-space: nowrap;\n pointer-events: none;\n font-size: 12px;\n font-weight: 500;\n}\n\n/* Light floating bars: section toolbar, rich text bar, heading format bar */\n.bm-toolbar,\n.bm-rich {\n position: fixed;\n z-index: 3;\n display: flex;\n gap: 2px;\n padding: 4px;\n border-radius: 12px;\n background: #fff;\n color: var(--ink);\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-toolbar button,\n.bm-rich button {\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: inherit;\n min-height: 32px;\n padding: 0 10px;\n font-size: 12px;\n font-weight: 500;\n}\n.bm-toolbar button:hover:not(:disabled),\n.bm-rich button:hover {\n background: var(--fill);\n}\n.bm-rich button[aria-pressed=\"true\"] {\n background: var(--bm-saved-bg);\n box-shadow: inset 0 0 0 1px oklch(0.46 0.13 145 / 0.4);\n}\n.bm-toolbar :focus-visible,\n.bm-rich :focus-visible {\n outline-color: var(--accent);\n}\n.bm-toolbar {\n align-items: center;\n max-width: calc(100vw - 16px);\n padding: 5px;\n}\n.bm-toolbar button {\n width: 34px;\n min-height: 34px;\n height: 34px;\n padding: 0;\n border-radius: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: oklch(0.4 0.01 255);\n}\n.bm-toolbar button:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n.bm-toolbar button:disabled {\n opacity: 0.35;\n cursor: default;\n}\n.bm-toolbar .bm-danger {\n color: var(--bm-danger-icon);\n}\n.bm-toolbar .bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-toolbar-active {\n box-shadow:\n 0 0 0 2px var(--bm-primary),\n 0 10px 24px -12px oklch(0.2 0.02 255 / 0.35);\n}\n.bm-toolbar-name {\n display: block;\n max-width: 16rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n padding: 0 12px 0 10px;\n}\n.bm-toolbar-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--bm-ink);\n}\n.bm-toolbar-anchor {\n font-family: var(--mono);\n font-size: 12px;\n font-weight: 400;\n color: var(--bm-muted);\n}\n.bm-sep {\n width: 1px;\n align-self: stretch;\n margin: 4px 2px;\n background: var(--line);\n}\n.bm-toolbar .bm-sep {\n align-self: center;\n height: 20px;\n margin: 0 4px;\n background: oklch(0.9 0.005 250);\n}\n.bm-icon {\n width: 16px;\n height: 16px;\n display: block;\n}\n.bm-rich {\n align-items: center;\n flex-wrap: wrap;\n max-width: calc(100vw - 16px);\n}\n.bm-rich button {\n min-height: 32px;\n min-width: 32px;\n}\n.bm-rich input {\n width: 168px;\n min-height: 30px;\n padding: 0 8px;\n border: 0;\n border-radius: 7px;\n background: var(--fill);\n color: var(--ink);\n font-size: 12px;\n}\n.bm-rich input:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--accent);\n}\n\n/* Heading format bar: each button shows \"Aa\" in its own weight or font over a mono caption. */\n.bm-rich.bm-format-bar {\n flex-wrap: nowrap;\n}\n.bm-rich.bm-format-bar button.bm-fmt {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n min-width: 42px;\n height: 48px;\n min-height: 48px;\n padding: 0 8px;\n border-radius: 8px;\n}\n.bm-fmt-sample {\n font-size: 15px;\n line-height: 1;\n color: var(--bm-ink);\n}\n.bm-fmt-caption {\n font-family: var(--mono);\n font-size: 9px;\n letter-spacing: 0.02em;\n color: var(--bm-muted);\n}\n.bm-rich.bm-format-bar button.bm-fmt[aria-pressed=\"true\"] {\n background: var(--bm-saved-bg);\n box-shadow: inset 0 0 0 1px oklch(0.46 0.13 145 / 0.4);\n}\n.bm-format-bar .bm-sep {\n align-self: stretch;\n margin: 6px 4px;\n}\n\n/* Light popovers: add menu, section picker, edit link */\n.bm-popover {\n position: fixed;\n z-index: 3;\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 180px;\n max-height: min(420px, calc(100vh - 16px));\n overflow: auto;\n padding: 6px;\n border-radius: 12px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-popover > button {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 34px;\n padding: 0 10px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n text-align: left;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-popover > button:hover {\n background: var(--fill);\n}\n\n/* Add section picker: wireframe cards */\n.bm-popover[aria-label=\"Add section\"][role=\"listbox\"] {\n gap: 14px;\n width: 640px;\n max-width: calc(100vw - 16px);\n max-height: calc(100vh - 16px);\n padding: 16px;\n border-radius: 14px;\n overflow: visible;\n box-shadow: var(--bm-shadow-dialog);\n}\n.bm-picker-head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.bm-picker-title {\n font-size: 17px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n.bm-picker-where {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n color: var(--bm-muted);\n}\n.bm-picker-grid {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 10px;\n max-height: 26rem;\n overflow-y: auto;\n padding: 2px 6px 2px 2px;\n margin-right: -6px;\n scrollbar-gutter: stable;\n}\n.bm-popover .bm-picker-grid > button {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: flex-start;\n gap: 6px;\n min-height: 0;\n padding: 8px 8px 10px;\n border: 1px solid oklch(0.9 0.005 250);\n border-radius: 10px;\n background: #fff;\n text-align: left;\n font-weight: 400;\n}\n.bm-popover .bm-picker-grid > button:hover {\n background: #fff;\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px oklch(0.46 0.13 145 / 0.12);\n}\n.bm-wire {\n position: relative;\n display: block;\n width: 100%;\n height: 76px;\n border-radius: 7px;\n background: oklch(0.97 0 0);\n overflow: hidden;\n}\n.bm-wire > span {\n position: absolute;\n display: block;\n}\n.bm-type-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 0 2px;\n}\n.bm-type-name {\n font-size: 14px;\n font-weight: 600;\n line-height: 1.25;\n color: var(--bm-ink);\n}\n.bm-type-variants {\n font-family: var(--mono);\n font-size: 10px;\n font-weight: 400;\n line-height: 1.35;\n white-space: nowrap;\n color: var(--muted);\n}\n.bm-type-desc {\n padding: 0 2px;\n font-size: 12px;\n line-height: 1.4;\n color: var(--bm-help);\n}\n.bm-picker-note {\n margin: 0;\n font-size: 12px;\n color: var(--bm-muted);\n}\n\n.bm-popover[aria-label=\"Edit link\"] {\n gap: 14px;\n padding: 16px;\n max-height: calc(100vh - 16px);\n}\n\n/* Dialogs and banners */\n.bm-dialog {\n position: fixed;\n z-index: 6;\n display: flex;\n flex-direction: column;\n gap: 16px;\n width: min(400px, calc(100vw - 32px));\n padding: 20px;\n border-radius: 14px;\n background: #fff;\n box-shadow: var(--bm-shadow-dialog);\n}\n.bm-dialog-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n.bm-dialog-heading {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.bm-dialog-sub {\n margin: 0;\n font-size: 13px;\n line-height: 1.4;\n color: var(--bm-help);\n}\n.bm-dialog .bm-dialog-x,\n.bm-popover .bm-dialog-x,\n.bm-modal .bm-dialog-x {\n flex: none;\n width: 32px;\n height: 32px;\n margin: -6px -8px -6px 0;\n background: transparent;\n color: var(--bm-icon);\n}\n.bm-dialog-title {\n margin: 0;\n font-size: 17px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--bm-ink);\n}\n.bm-popover .bm-dialog-title {\n font-size: 16px;\n}\n.bm-dialog .bm-note {\n color: var(--bm-label);\n font-size: 14px;\n line-height: 1.5;\n}\n.bm-dialog button,\n.bm-popover .bm-actions button,\n.bm-banner button {\n min-height: 38px;\n padding: 0 16px;\n border: 0;\n border-radius: 8px;\n background: var(--fill);\n font-size: 14px;\n font-weight: 400;\n}\n.bm-dialog button:hover:not(:disabled),\n.bm-popover .bm-actions button:hover:not(:disabled) {\n background: var(--fill-hover);\n}\n/* The primary action comes first in the DOM (focus lands on it); row-reverse shows it last, on the right. */\n.bm-actions {\n display: flex;\n flex-direction: row-reverse;\n justify-content: flex-start;\n align-items: center;\n gap: 8px;\n}\n.bm-dialog > .bm-actions,\n.bm-popover[aria-label=\"Edit link\"] > .bm-actions {\n padding-top: 12px;\n border-top: 1px solid var(--bm-divider);\n}\n.bm-dialog-foot {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 12px;\n border-top: 1px solid var(--bm-divider);\n}\n.bm-dialog-foot > .bm-hint {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n.bm-dialog-foot .bm-actions {\n flex: none;\n}\n\n/* Alert dialogs: [icon tile] [title / body / note] [x] */\n.bm-alert-main {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n.bm-alert-copy {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.bm-alert-body {\n margin: 0;\n font-size: 14px;\n line-height: 1.5;\n color: var(--bm-label);\n overflow-wrap: anywhere;\n}\n.bm-alert-body strong {\n font-weight: 600;\n color: var(--bm-ink);\n}\n.bm-alert-note {\n margin: 0;\n font-size: 12px;\n line-height: 1.45;\n color: var(--bm-muted);\n}\n.bm-tile {\n flex: none;\n display: grid;\n place-items: center;\n width: 36px;\n height: 36px;\n border-radius: 9px;\n}\n.bm-tile .bm-icon {\n width: 18px;\n height: 18px;\n}\n.bm-tile-warn {\n background: var(--bm-unsaved-bg);\n color: var(--bm-unsaved-fg);\n}\n.bm-tile-danger {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-tile-neutral {\n background: var(--bm-fill);\n color: var(--bm-label);\n}\n\n.bm-banner {\n position: fixed;\n z-index: 6;\n display: flex;\n align-items: center;\n gap: 12px;\n width: min(440px, calc(100vw - 32px));\n padding: 12px 14px;\n border-radius: 12px;\n box-shadow: 0 14px 34px -10px oklch(0.2 0.02 255 / 0.4);\n}\n.bm-banner button {\n min-height: 34px;\n padding: 0 14px;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-banner-ink {\n background: var(--ink);\n color: #fff;\n}\n.bm-banner-light {\n background: #fff;\n box-shadow: var(--shadow-pop);\n}\n.bm-banner-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.bm-banner-title {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.35;\n}\n.bm-banner-sub {\n margin: 0;\n font-size: 12px;\n line-height: 1.4;\n opacity: 0.7;\n}\n.bm-banner .bm-actions {\n flex: none;\n gap: 6px;\n}\n.bm-banner-ink button {\n min-height: 30px;\n padding: 0 12px;\n font-size: 12px;\n background: oklch(1 0 0 / 0.12);\n color: #fff;\n}\n.bm-banner-ink button:hover {\n background: oklch(1 0 0 / 0.2);\n}\n.bm-banner-ink .bm-primary {\n background: #fff;\n color: var(--ink);\n}\n.bm-banner-ink .bm-primary:hover {\n background: oklch(0.94 0.003 250);\n}\n.bm-banner-ink :focus-visible {\n outline-color: oklch(0.82 0.14 145);\n}\n.bm-dot-stale {\n background: oklch(0.7 0.18 25) !important;\n}\n.bm-dot-info {\n background: var(--info-dot) !important;\n}\n\n/* Closed editor. The dock sits where the sidebar header's controls sit: header padding (top 14, right 14) minus the dock's 7px padding. */\n.bm-dock {\n position: fixed;\n z-index: 5;\n top: 7px;\n right: 7px;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 7px 7px 10px;\n border-radius: 14px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-dot {\n flex: none;\n width: 8px;\n height: 8px;\n border-radius: 99px;\n background: oklch(0.72 0.17 145);\n}\n.bm-dot-dirty {\n background: var(--warn-dot);\n}\n\n/* Sidebar shell */\n.bm-sidebar {\n position: fixed;\n z-index: 4;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(440px, 100vw);\n display: flex;\n flex-direction: column;\n background: #fff;\n box-shadow:\n 0 0 0 1px var(--line),\n -24px 0 48px -24px oklch(0.2 0.02 255 / 0.25);\n}\n.bm-resize {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: col-resize;\n touch-action: none;\n z-index: 2;\n}\n.bm-resize:hover,\n.bm-resize:focus-visible {\n background: oklch(0.46 0.13 145 / 0.25);\n}\n.bm-resize:focus-visible {\n outline-offset: -2px;\n}\n\n.bm-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 14px 14px 16px;\n border-bottom: 1px solid var(--line-soft);\n}\n.bm-mark {\n flex: none;\n display: block;\n width: 28px;\n height: auto;\n aspect-ratio: 21 / 19;\n image-rendering: pixelated;\n user-select: none;\n}\n/* Bear, name and slogan. Takes the space the controls leave; the text fades out when it no longer fits. */\n.bm-brand {\n position: relative;\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.bm-head-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n transition: opacity 160ms ease;\n}\n.bm-brand-compact .bm-head-text {\n opacity: 0;\n}\n/* The same two lines, in a card left of the sidebar (over the page), level with the header, while the pointer is on\n the brand. 16px is the header's left padding: the card clears the sidebar edge by 10px. */\n.bm-brand-tip {\n position: absolute;\n z-index: 5;\n top: 50%;\n right: calc(100% + 16px + 10px);\n display: flex;\n flex-direction: column;\n padding: 8px 12px;\n border-radius: 10px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n white-space: nowrap;\n opacity: 0;\n transform: translate(4px, -50%);\n pointer-events: none;\n transition:\n opacity 120ms ease,\n transform 120ms ease;\n}\n.bm-brand-compact:hover .bm-brand-tip {\n opacity: 1;\n transform: translate(0, -50%);\n transition-delay: 120ms;\n}\n@media (prefers-reduced-motion: reduce) {\n .bm-head-text,\n .bm-brand-tip {\n transition: none;\n }\n}\n/* A ring with one open quarter that turns while a save is written and the page reloads. */\n.bm-spin {\n flex: none;\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: bm-spin 0.8s linear infinite;\n}\n@keyframes bm-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .bm-spin {\n animation: none;\n }\n}\n.bm-faces {\n display: grid;\n}\n.bm-face {\n grid-area: 1 / 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n white-space: nowrap;\n}\n.bm-face[hidden-face] {\n visibility: hidden;\n}\n.bm-save:disabled {\n opacity: 0.85;\n cursor: progress;\n}\n.bm-head-title {\n font-size: 15px;\n font-weight: 600;\n letter-spacing: -0.015em;\n /* The controls beside it never shrink, so a narrow sidebar cuts the name, not the buttons. */\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-head-sub {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-pill {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 10px;\n border-radius: 999px;\n background: var(--bm-saved-bg);\n color: var(--bm-saved-fg);\n font-size: 12px;\n font-weight: 500;\n}\n.bm-pill .bm-dot {\n width: 6px;\n height: 6px;\n background: var(--accent);\n}\n.bm-pill-dirty {\n background: var(--warn-tint);\n color: var(--warn-ink);\n}\n.bm-pill-dirty .bm-dot {\n background: var(--warn-dot);\n}\nbutton.bm-pill-btn {\n min-height: 0;\n padding: 0 10px;\n border: 0;\n border-radius: 999px;\n background: var(--warn-tint);\n color: var(--warn-ink);\n font-family: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n}\n:is(.bm-sidebar, .bm-dock) button.bm-pill-btn:hover:not(:disabled) {\n background: oklch(0.93 0.06 75);\n color: var(--warn-ink);\n}\nbutton.bm-pill-btn:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n.bm-dialog-wide {\n width: min(400px, calc(100vw - 32px));\n}\n.bm-dialog .bm-actions {\n flex-wrap: nowrap;\n}\n.bm-dialog .bm-actions button {\n flex: none;\n white-space: nowrap;\n}\n.bm-changes {\n width: min(540px, calc(100vw - 32px));\n}\n.bm-commit-files {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: min(34vh, 280px);\n overflow-y: auto;\n}\n.bm-commit-files label {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n cursor: pointer;\n}\n.bm-commit-mark {\n font:\n 600 11px / 1 ui-monospace,\n monospace;\n width: 18px;\n text-align: center;\n opacity: 0.7;\n}\n.bm-commit-msg {\n width: 100%;\n box-sizing: border-box;\n resize: vertical;\n font: inherit;\n font-size: 14px;\n padding: 8px 12px;\n border: 1px solid var(--line);\n border-radius: 8px;\n background: transparent;\n color: inherit;\n}\n\n/* Unsaved changes review and version history: groups, rows, diff lines */\n.bm-changes-list {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-height: 22rem;\n overflow-y: auto;\n margin: 0 -4px;\n padding: 0 4px;\n}\n.bm-changes-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-changes-area {\n margin: 0;\n display: flex;\n align-items: baseline;\n gap: 8px;\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--bm-section);\n}\n.bm-changes-file {\n font-weight: 400;\n letter-spacing: 0;\n text-transform: none;\n color: oklch(0.55 0.01 255);\n}\n.bm-changes-count {\n margin-left: auto;\n font-weight: 400;\n letter-spacing: 0;\n color: var(--bm-muted);\n}\n.bm-changes ul {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n overflow: hidden;\n}\n.bm-change {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 10px;\n font-size: 14px;\n line-height: 1.4;\n}\n.bm-change + .bm-change {\n border-top: 1px solid var(--bm-divider);\n}\n.bm-change-mark {\n flex: none;\n display: grid;\n place-items: center;\n width: 22px;\n height: 22px;\n border-radius: 6px;\n font-family: var(--mono);\n font-size: 13px;\n font-weight: 600;\n background: var(--bm-unsaved-bg);\n color: var(--bm-unsaved-fg);\n}\n.bm-change-added .bm-change-mark {\n background: var(--bm-badge-green-bg);\n color: var(--bm-badge-green-fg);\n}\n.bm-change-removed .bm-change-mark {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-text);\n}\n.bm-change-body {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.bm-change-field {\n font-weight: 500;\n color: var(--bm-ink);\n overflow-wrap: anywhere;\n}\n.bm-change-values {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n.bm-change-values del,\n.bm-change-values ins {\n display: flex;\n gap: 6px;\n min-width: 0;\n padding: 3px 7px;\n border-radius: 5px;\n text-decoration: none;\n font-size: 13px;\n}\n.bm-change-values del {\n background: var(--bm-diff-del-bg);\n color: var(--bm-diff-del-fg);\n}\n.bm-change-values ins {\n background: var(--bm-diff-add-bg);\n color: var(--bm-diff-add-fg);\n}\n.bm-change-values del::before {\n content: \"\\2212\";\n flex: none;\n font-family: var(--mono);\n}\n.bm-change-values ins::before {\n content: \"+\";\n flex: none;\n font-family: var(--mono);\n}\n.bm-change-values del > span,\n.bm-change-values ins > span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-change-values del > span {\n text-decoration: line-through;\n text-decoration-color: oklch(0.45 0.13 25 / 0.5);\n}\n.bm-changes-empty {\n margin: 0;\n padding: 24px 0;\n text-align: center;\n font-size: 14px;\n color: var(--bm-muted);\n}\n\n.bm-changes ul.bm-versions {\n gap: 0;\n}\n.bm-version {\n padding: 0;\n}\n.bm-version + .bm-version {\n border-top: 1px solid var(--bm-divider);\n}\n.bm-version-when strong {\n font-weight: 600;\n}\n.bm-tipped {\n position: relative;\n}\n.bm-tipped::after {\n content: attr(data-tip);\n position: absolute;\n right: calc(100% + 6px);\n top: 50%;\n transform: translateY(-50%);\n padding: 4px 8px;\n border-radius: 6px;\n background: var(--ink);\n color: #fff;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.3;\n white-space: nowrap;\n pointer-events: none;\n visibility: hidden;\n z-index: 5;\n}\n.bm-version-row > .bm-tipped:first-child::after {\n right: auto;\n left: calc(100% + 6px);\n}\n.bm-tipped:hover::after,\n.bm-tipped:focus-visible::after {\n visibility: visible;\n}\n.bm-version-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 8px 8px 10px;\n}\n.bm-version-when {\n flex: 1;\n min-width: 0;\n margin-right: auto;\n padding: 0 !important;\n min-height: 32px !important;\n font-weight: 500;\n display: flex !important;\n flex-direction: column;\n align-items: flex-start !important;\n justify-content: center;\n gap: 2px;\n text-align: left;\n}\n.bm-version-line {\n display: flex;\n align-items: baseline;\n gap: 8px;\n}\n.bm-version-sum {\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 400;\n color: var(--bm-help);\n}\n.bm-version-row .bm-restore {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex: none;\n min-height: 32px;\n padding: 0 10px;\n border-radius: 7px;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-version-rel {\n font-size: 14px;\n font-weight: 500;\n color: var(--bm-ink);\n}\n.bm-version-abs {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--bm-muted);\n}\n.bm-version-diff {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 4px 10px 12px 10px;\n border-top: 1px solid var(--bm-divider);\n margin-top: 0;\n}\n.bm-version-diff ul {\n margin: 0;\n}\n.bm-day {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.bm-restored {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 8px 8px 12px;\n border-radius: 9px;\n background: var(--bm-diff-add-bg);\n color: var(--bm-saved-fg);\n font-size: 13px;\n}\n.bm-restored > span {\n flex: 1;\n min-width: 0;\n}\n\n.bm-tabs {\n display: flex;\n gap: 0;\n padding: 0 12px;\n overflow-x: auto;\n border-bottom: 1px solid var(--bm-tab-rule);\n}\n.bm-tabs button {\n flex: 1 1 auto;\n height: 46px;\n padding: 0 6px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: oklch(0.48 0.01 255);\n font-size: 13px;\n font-weight: 400;\n}\n.bm-tabs button:hover {\n color: var(--ink);\n background: var(--fill-soft);\n}\n.bm-tabs button[aria-selected=\"true\"] {\n color: var(--ink);\n background: transparent;\n font-weight: 600;\n box-shadow: inset 0 -2px 0 var(--accent);\n}\n.bm-tabs button:focus-visible {\n outline-offset: -2px;\n}\n\n.bm-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 24px 24px 32px;\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n.bm-foot {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n padding: 12px 16px;\n border-top: 1px solid var(--line-soft);\n font-family: var(--mono);\n font-size: 10px;\n color: var(--muted);\n}\n.bm-foot span:first-child {\n flex: none;\n white-space: nowrap;\n}\n.bm-foot span:last-child {\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n/* Group header: mono 11/500, then a 1px rule. With a right-hand item the rule sits on the flex wrapper. */\n.bm-group {\n margin: 18px 0 0;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--bm-divider);\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--bm-section);\n}\n.bm-group:first-child {\n margin-top: 0;\n}\n.bm-stack-tight > .bm-group {\n margin-bottom: 10px;\n}\n.bm-meta {\n margin: 0;\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n}\n\n/* Fields */\n.bm-label {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--bm-label);\n}\n.bm-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-hint {\n font-size: 12px;\n line-height: 1.45;\n font-weight: 400;\n color: var(--muted);\n}\n.bm-label-text {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n}\n.bm-info {\n position: relative;\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n margin-left: 4px;\n}\n.bm-info-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n margin: -3px 0;\n border-radius: 999px;\n color: var(--bm-info);\n cursor: help;\n text-transform: none;\n letter-spacing: 0;\n}\n.bm-info-btn:hover,\n.bm-info-btn[aria-expanded=\"true\"] {\n color: var(--ink);\n}\n.bm-info-btn:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 1px;\n}\n.bm-tip {\n position: fixed;\n z-index: 2147483647;\n visibility: hidden;\n pointer-events: none;\n padding: 8px 10px;\n border-radius: 8px;\n box-sizing: border-box;\n background: var(--ink);\n color: oklch(0.98 0.003 250);\n font-family: var(--sans, inherit);\n font-size: 12px;\n line-height: 1.45;\n font-weight: 400;\n text-transform: none;\n letter-spacing: 0;\n text-align: left;\n white-space: normal;\n box-shadow: 0 6px 20px rgb(0 0 0 / 0.25);\n}\n.bm-tip-open {\n visibility: visible;\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo, .bm-consent) :where(input:not([type=\"checkbox\"]):not([type=\"file\"]), select, textarea) {\n width: 100%;\n min-height: 40px;\n padding: 0 12px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n color: var(--ink);\n font-size: 14px;\n font-weight: 400;\n outline: none;\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo, .bm-consent) textarea {\n padding: 8px 12px;\n min-height: 72px;\n line-height: 1.5;\n resize: vertical;\n}\n:is(.bm-sidebar, .bm-popover) select:not([size]) {\n appearance: none;\n padding-right: 32px;\n /* A caret made of gradients, not a `data:` image: a site's Content-Security-Policy can block those. */\n background-image: linear-gradient(45deg, transparent 50%, #777 50%), linear-gradient(135deg, #777 50%, transparent 50%);\n background-size: 6px 6px;\n background-repeat: no-repeat;\n background-position:\n right 17px center,\n right 12px center;\n}\n.bm-sidebar select[size],\n.bm-popover select[size] {\n padding: 4px;\n font-size: 12px;\n}\n.bm-sidebar select[size] option,\n.bm-sidebar select[size] optgroup,\n.bm-popover select[size] option,\n.bm-popover select[size] optgroup {\n padding: 3px 6px;\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo, .bm-consent) :where(input:not([type=\"checkbox\"]):not([type=\"file\"]), select, textarea):focus {\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px var(--bm-primary-ring);\n}\n:is(.bm-sidebar, .bm-popover, .bm-seo, .bm-consent) :where(input[aria-label=\"Link URL\"], .bm-mono) {\n font-family: var(--mono);\n font-size: 13px;\n}\n.bm-prefix-wrap {\n display: flex;\n align-items: center;\n min-height: 40px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n overflow: hidden;\n}\n.bm-prefix-wrap:focus-within {\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px var(--bm-primary-ring);\n}\n.bm-prefix {\n padding: 0 2px 0 12px;\n font-family: var(--mono);\n font-size: 13px;\n color: var(--muted);\n}\n.bm-prefix-wrap input {\n border: 0;\n box-shadow: none !important;\n min-height: 38px;\n padding-left: 2px;\n font-family: var(--mono);\n font-size: 13px;\n}\n.bm-stack {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n.bm-stack-tight {\n gap: 8px;\n}\n.bm-groups {\n gap: 36px;\n}\n.bm-list {\n display: flex;\n flex-direction: column;\n border-radius: 10px;\n box-shadow: 0 0 0 1px var(--bm-border);\n overflow: hidden;\n}\n.bm-list-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px 8px 12px;\n border-bottom: 1px solid var(--line-soft);\n}\n.bm-list-row:last-child {\n border-bottom: 0;\n}\n.bm-list-row-on {\n background: var(--accent-tint);\n}\n.bm-list-row a {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n color: var(--ink);\n text-decoration: none;\n}\n.bm-list-row a:hover .bm-list-title {\n text-decoration: underline;\n}\n.bm-list-title {\n font-size: 14px;\n font-weight: 500;\n}\n.bm-list-path {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n}\n.bm-badge-home {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n background: var(--bm-badge-green-bg);\n color: var(--bm-badge-green-fg);\n}\n.bm-badge {\n font-family: var(--mono);\n font-size: 11px;\n padding: 3px 7px;\n border-radius: 5px;\n background: var(--bm-badge-amber-bg);\n color: var(--bm-badge-amber-fg);\n}\n.bm-badge-system {\n background: var(--fill);\n color: var(--ink-2);\n}\n.bm-badge-on {\n background: var(--bm-badge-green-bg);\n color: var(--bm-badge-green-fg);\n}\n.bm-row {\n display: flex;\n gap: 6px;\n align-items: center;\n flex-wrap: wrap;\n}\n.bm-row-split {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n}\n.bm-error {\n color: var(--danger-ink);\n font-size: 12px;\n font-weight: 400;\n margin: 0;\n}\n.bm-warn {\n color: var(--warn-ink);\n font-size: 12px;\n margin: 0;\n}\n.bm-note {\n margin: 0;\n color: var(--bm-help);\n font-size: 13px;\n line-height: 1.55;\n font-weight: 400;\n}\n.bm-group + .bm-note,\n.bm-group-split + .bm-note {\n margin-top: -4px;\n}\n\n/* Switch: 36 x 20, knob 16 inset 2 */\n.bm-check {\n flex-direction: row;\n align-items: center;\n gap: 10px;\n font-weight: 500;\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"] {\n appearance: none;\n position: relative;\n flex: none;\n width: 36px;\n height: 20px;\n margin: 0;\n border-radius: 999px;\n background: var(--bm-switch-off);\n cursor: pointer;\n transition: background 0.15s;\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"]::before {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: #fff;\n box-shadow: 0 1px 2px oklch(0 0 0 / 0.2);\n transition: transform 0.15s;\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"]:checked {\n background: var(--bm-primary);\n}\n:is(.bm-check, .bm-switch-row) input[type=\"checkbox\"]:checked::before {\n transform: translateX(16px);\n}\n.bm-popover .bm-check {\n color: var(--bm-label);\n font-size: 14px;\n}\n\n/* Buttons inside the sidebar */\n.bm-sidebar :where(button:not([role=\"tab\"]):not([role=\"radio\"]):not(.bm-resize)) {\n min-height: 32px;\n padding: 0 12px;\n border: 0;\n border-radius: 8px;\n background: var(--fill);\n color: var(--ink);\n font-size: 13px;\n font-weight: 500;\n}\n.bm-sidebar :where(button:not([role=\"tab\"]):not([role=\"radio\"]):not(.bm-resize)):hover:not(:disabled) {\n background: var(--fill-hover);\n}\n.bm-sidebar button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n/* Dashed \"Add ...\" buttons: Add link, Add button, Add column, Add item */\n.bm-sidebar .bm-add {\n min-height: 44px;\n background: oklch(0.985 0.002 250);\n color: var(--bm-link);\n border: 1px dashed oklch(0.85 0.005 250);\n border-radius: 8px;\n}\n.bm-sidebar .bm-add:hover:not(:disabled) {\n background: var(--accent-tint);\n}\n\n/* Cards, lists, images */\n.bm-card {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n}\n.bm-card .bm-card {\n background: var(--bm-fill-nested);\n border-color: var(--line-soft);\n}\n.bm-card > .bm-label:first-child:not(:only-child) {\n font-family: var(--mono);\n font-size: 11px;\n letter-spacing: 0.04em;\n font-weight: 500;\n color: var(--muted);\n}\n.bm-card[draggable=\"true\"] {\n cursor: grab;\n}\n/* Drag and drop: the target shows what a drop would do. */\n.bm-dragging {\n opacity: 0.4;\n}\n.bm-drop-before,\n.bm-drop-after,\n.bm-drop-child {\n --drop: var(--accent);\n}\n.bm-drop-before::before,\n.bm-drop-after::before {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n height: 3px;\n border-radius: 3px;\n background: var(--drop);\n box-shadow: 0 0 0 2px var(--accent-ring);\n pointer-events: none;\n z-index: 2;\n}\n.bm-drop-before::before {\n top: -6px;\n}\n.bm-drop-after::before {\n bottom: -6px;\n}\n.bm-drop-child {\n box-shadow: inset 0 0 0 2px var(--drop);\n background: var(--accent-tint);\n}\n.bm-drop-before::after,\n.bm-drop-after::after,\n.bm-drop-child::after,\n.bm-drop-files::after {\n content: attr(data-drop-hint);\n position: absolute;\n right: 8px;\n padding: 3px 8px;\n border-radius: 6px;\n background: var(--ink);\n color: #fff;\n font-size: 11px;\n font-weight: 500;\n line-height: 1.3;\n white-space: nowrap;\n pointer-events: none;\n z-index: 3;\n}\n.bm-drop-before::after {\n top: -22px;\n}\n.bm-drop-after::after {\n bottom: -22px;\n}\n.bm-drop-child::after {\n top: -11px;\n right: 12px;\n}\n.bm-drop-files {\n box-shadow: inset 0 0 0 2px var(--accent);\n background: var(--accent-tint);\n}\n.bm-drop-files::after {\n top: -11px;\n right: 12px;\n}\n.bm-thumb {\n width: 100%;\n height: 96px;\n object-fit: cover;\n border-radius: 7px;\n background: var(--fill);\n}\n.bm-drop {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px dashed var(--line);\n border-radius: 10px;\n padding: 10px;\n background: var(--fill-soft);\n}\n.bm-drop input[type=\"file\"] {\n width: 100%;\n font-size: 12px;\n color: var(--muted);\n}\n.bm-drop input[type=\"file\"]::file-selector-button {\n height: 32px;\n margin-right: 10px;\n padding: 0 12px;\n border: 0;\n border-radius: 7px;\n background: var(--ink);\n color: #fff;\n font: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n}\n.bm-alert {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 14px;\n border-radius: 12px;\n background: var(--danger-tint);\n box-shadow: 0 0 0 1px oklch(0.55 0.18 25 / 0.35);\n}\n.bm-alert-title {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--danger-ink);\n}\n.bm-alert .bm-error {\n font-family: var(--mono);\n font-size: 11px;\n}\n.bm-alert-notice {\n background: var(--warn-tint);\n box-shadow: 0 0 0 1px oklch(0.45 0.09 65 / 0.2);\n}\n.bm-alert-notice .bm-note {\n color: var(--warn-ink);\n font-size: 12px;\n}\n\n/* Header actions */\n.bm-save {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 34px;\n padding: 0 12px;\n border: 0;\n border-radius: 8px;\n background: var(--accent);\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n}\n.bm-dialog .bm-primary kbd {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n margin-left: 8px;\n opacity: 0.8;\n}\n.bm-save kbd {\n font-family: var(--mono);\n font-size: 10px;\n font-weight: 400;\n opacity: 0.75;\n}\n/* Icon buttons: 32 x 32, transparent, grey icon, grey fill on hover. */\n.bm-icon-btn {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: 32px;\n height: 32px;\n min-height: 0 !important;\n padding: 0 !important;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--bm-icon);\n}\n.bm-icon-btn:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n.bm-icon-btn:disabled {\n opacity: 0.35;\n}\n.bm-close {\n width: 32px;\n height: 32px;\n background: transparent;\n color: var(--bm-icon);\n border-radius: 7px;\n}\n.bm-close:hover:not(:disabled) {\n background: var(--fill) !important;\n color: var(--ink);\n}\n.bm-dock .bm-save {\n font-family: var(--sans);\n}\n.bm-split {\n position: relative;\n display: inline-flex;\n flex: none;\n}\n.bm-split .bm-split-main {\n border-radius: 8px 0 0 8px;\n}\n.bm-split .bm-split-toggle {\n width: 28px;\n padding: 0;\n justify-content: center;\n border-radius: 0 8px 8px 0;\n box-shadow: inset 1px 0 0 oklch(1 0 0 / 0.35);\n}\n.bm-split .bm-split-toggle:focus-visible,\n.bm-split .bm-split-main:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n.bm-split-menu {\n position: absolute;\n z-index: 8;\n top: calc(100% + 6px);\n right: 0;\n min-width: 200px;\n display: flex;\n flex-direction: column;\n padding: 4px;\n border-radius: 10px;\n background: #fff;\n box-shadow: var(--bm-shadow-pop);\n}\n.bm-split-menu button.bm-split-item {\n display: flex;\n align-items: center;\n width: 100%;\n min-height: 34px;\n padding: 0 10px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--ink);\n font-family: var(--sans);\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n}\n.bm-split-menu button.bm-split-item:hover:not(:disabled),\n.bm-split-menu button.bm-split-item:focus-visible {\n background: var(--fill);\n outline: none;\n}\n.bm-split-menu button.bm-split-danger {\n color: var(--danger-ink);\n}\n.bm-split-menu button.bm-split-item {\n justify-content: space-between;\n gap: 16px;\n}\n.bm-split-menu button.bm-split-item kbd {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--muted);\n}\n.bm-split-menu button.bm-split-sep {\n margin-top: 5px;\n position: relative;\n}\n.bm-split-menu button.bm-split-sep::before {\n content: \"\";\n position: absolute;\n left: 6px;\n right: 6px;\n top: -3px;\n height: 1px;\n background: var(--line);\n}\n.bm-split-menu button.bm-split-danger:hover:not(:disabled),\n.bm-split-menu button.bm-split-danger:focus-visible {\n background: var(--danger-tint);\n}\n.bm-split-menu button.bm-split-item:disabled {\n opacity: 0.45;\n cursor: default;\n}\n.bm-sidebar .bm-icon-btn.bm-danger {\n color: var(--bm-danger-icon);\n}\n.bm-sidebar .bm-icon-btn.bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-small {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n min-height: 28px !important;\n padding: 0 10px !important;\n font-family: var(--sans);\n font-size: 12px !important;\n letter-spacing: 0;\n text-transform: none;\n align-self: flex-start;\n}\n.bm-group-split {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-top: 18px;\n margin-bottom: 0;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--bm-divider);\n}\n.bm-group-split:first-child {\n margin-top: 0;\n}\n.bm-group-split > .bm-group {\n margin: 0;\n padding: 0;\n border: 0;\n}\n.bm-group-split .bm-small {\n text-transform: none;\n letter-spacing: 0;\n}\n.bm-group-split span.bm-small {\n font-family: var(--mono);\n font-size: 11px !important;\n font-weight: 400;\n color: var(--bm-muted);\n padding: 0 !important;\n min-height: 0 !important;\n}\n.bm-stack-tight > .bm-group-split {\n margin-bottom: 10px;\n}\n\n/* Labels with a right-hand tag */\n.bm-label.bm-label-row,\n.bm-label-row {\n flex-direction: row;\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 8px;\n}\n.bm-meta-tag {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n letter-spacing: 0;\n color: var(--bm-muted);\n}\n\n/* Switch rows */\n.bm-switch-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n cursor: pointer;\n}\n.bm-switch-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n.bm-switch-title {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n font-weight: 500;\n color: var(--bm-label);\n}\n\n/* Tone cards and segmented controls */\n.bm-tones {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 6px;\n}\n:is(.bm-sidebar, .bm-popover) .bm-tone {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 6px;\n min-height: 0;\n padding: 5px 5px 6px;\n border-radius: 9px;\n background: #fff;\n border: 0;\n box-shadow: inset 0 0 0 1px var(--bm-border);\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n}\n:is(.bm-sidebar, .bm-popover) .bm-tone:hover {\n background: var(--fill-soft);\n}\n:is(.bm-sidebar, .bm-popover) .bm-tone[aria-checked=\"true\"] {\n box-shadow: inset 0 0 0 2px var(--accent);\n background: #fff;\n}\n.bm-tones-2 {\n grid-template-columns: repeat(2, 1fr);\n}\n.bm-tones-3 {\n grid-template-columns: repeat(3, 1fr);\n}\n/* A miniature of each button look, drawn with the editor's colours so it does not depend on the site theme. */\n.bm-btnsample {\n display: grid;\n place-items: center;\n height: 26px;\n border-radius: 6px;\n background: var(--fill-soft);\n}\n.bm-btnsample > span {\n display: block;\n font-size: 10px;\n font-weight: 600;\n line-height: 1;\n}\n.bm-btnsample-default > span {\n color: var(--ink-2);\n}\n.bm-btnsample-primary > span {\n padding: 5px 12px;\n border-radius: 999px;\n background: var(--accent);\n color: #fff;\n}\n.bm-btnsample-secondary > span {\n padding: 5px 12px;\n border-radius: 999px;\n color: var(--ink);\n box-shadow: inset 0 0 0 1px var(--ink-2);\n}\n.bm-btnsample-tertiary > span {\n color: var(--accent);\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n.bm-swatch {\n display: inline-block;\n flex: none;\n width: 10px;\n height: 10px;\n border-radius: 3px;\n box-shadow: inset 0 0 0 1px oklch(0.2 0.02 255 / 0.15);\n}\n.bm-swatch-lg {\n display: block;\n width: auto;\n height: 22px;\n border-radius: 6px;\n}\n.bm-swatch-base {\n background: #fff;\n}\n.bm-swatch-subtle {\n background: oklch(0.96 0.005 250);\n}\n.bm-swatch-inverse {\n background: var(--ink);\n}\n.bm-swatch-brand {\n background: var(--accent);\n}\n.bm-segmented {\n display: flex;\n padding: 3px;\n border-radius: 9px;\n background: var(--bm-fill);\n}\n.bm-sidebar .bm-segmented button,\n.bm-dialog .bm-segmented button {\n flex: 1;\n min-height: 36px;\n height: 36px;\n padding: 0 8px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: oklch(0.45 0.01 255);\n font-size: 13px;\n font-weight: 400;\n}\n.bm-sidebar .bm-segmented button:hover:not(:disabled),\n.bm-dialog .bm-segmented button:hover:not(:disabled) {\n background: oklch(1 0 0 / 0.5);\n}\n.bm-sidebar .bm-segmented button[aria-checked=\"true\"],\n.bm-dialog .bm-segmented button[aria-checked=\"true\"] {\n background: #fff;\n color: var(--ink);\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-icon-picker {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));\n gap: 4px;\n padding: 3px;\n border-radius: 9px;\n background: var(--bm-fill);\n}\n.bm-sidebar .bm-icon-picker button {\n display: grid;\n place-items: center;\n min-height: 40px;\n height: 40px;\n padding: 0;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: oklch(0.45 0.01 255);\n}\n.bm-sidebar .bm-icon-picker button:hover {\n background: oklch(1 0 0 / 0.5);\n color: var(--ink);\n}\n.bm-sidebar .bm-icon-picker button[aria-checked=\"true\"] {\n background: #fff;\n color: var(--accent);\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-icon-picker svg {\n width: 20px;\n height: 20px;\n}\n.bm-actions-split {\n display: flex;\n gap: 8px;\n padding-top: 4px;\n}\n.bm-actions-split button {\n flex: 1;\n min-height: 40px !important;\n font-size: 14px !important;\n}\n.bm-sidebar .bm-actions-split .bm-danger {\n background: var(--bm-danger-soft);\n}\n\n/* Arrays, links, images */\n.bm-array {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-array-item {\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n overflow: hidden;\n}\n.bm-array-item summary {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 0 8px 0 10px;\n font-size: 14px;\n font-weight: 500;\n color: var(--ink);\n cursor: pointer;\n list-style: none;\n}\n.bm-array-item summary::-webkit-details-marker {\n display: none;\n}\n.bm-array-item summary:hover {\n background: var(--fill-soft);\n}\n.bm-array-summary {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-grip,\n.bm-chevron {\n display: inline-grid;\n place-items: center;\n color: oklch(0.65 0.01 255);\n}\n.bm-chevron {\n transition: transform 0.12s;\n}\ndetails[open] > summary .bm-chevron {\n transform: rotate(90deg);\n}\n.bm-array-body {\n display: flex;\n flex-direction: column;\n gap: 18px;\n padding: 12px;\n background: var(--bm-fill-nested);\n border-top: 1px solid var(--line-soft);\n}\n.bm-row-end {\n justify-content: flex-end;\n}\n.bm-sidebar .bm-add-row {\n width: 100%;\n}\n.bm-link-btn {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n min-height: 40px;\n padding: 0 12px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n text-align: left;\n color: var(--ink-2);\n}\n.bm-sidebar .bm-link-btn {\n background: #fff;\n border: 1px solid var(--bm-border);\n font-size: 14px;\n padding: 0 12px;\n}\n.bm-sidebar .bm-link-btn:hover:not(:disabled) {\n background: #fff;\n border-color: oklch(0.8 0.005 250);\n}\n.bm-link-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--ink);\n font-weight: 500;\n}\n.bm-link-href {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n max-width: 45%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-stripes {\n background: repeating-linear-gradient(135deg, oklch(0.93 0.004 250) 0 6px, oklch(0.965 0.003 250) 6px 12px);\n}\n\n/* Image field: label above, compact 56px row, alt text under it */\n.bm-imagefield {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bm-image-row {\n display: flex;\n gap: 10px;\n align-items: center;\n}\n.bm-image-row .bm-thumb {\n flex: none;\n width: 56px;\n height: 56px;\n border-radius: 6px;\n}\n.bm-image-meta {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n justify-content: center;\n}\n.bm-image-path {\n font-family: var(--mono);\n font-size: 12px;\n color: var(--bm-label);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-sidebar .bm-alt {\n min-height: 40px;\n font-size: 14px;\n}\n.bm-image-actions {\n flex-wrap: nowrap;\n gap: 6px;\n}\n.bm-image-actions > button:not(.bm-icon-btn) {\n flex: 1;\n min-height: 36px;\n font-size: 13px;\n}\n.bm-layout {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 2px;\n}\n.bm-layout-row {\n display: grid;\n grid-template-columns: 56px 1fr;\n align-items: center;\n column-gap: 10px;\n row-gap: 4px;\n}\n.bm-layout-row .bm-label {\n margin: 0;\n}\n.bm-layout-row .bm-layout-hint {\n grid-column: 2;\n}\n.bm-position {\n display: grid;\n grid-template-columns: repeat(3, 20px);\n grid-template-rows: repeat(3, 20px);\n gap: 3px;\n padding: 4px;\n width: max-content;\n border-radius: 8px;\n background: var(--fill);\n}\n.bm-sidebar .bm-position-cell {\n width: 20px;\n height: 20px;\n min-height: 0;\n padding: 0;\n border: 0;\n border-radius: 5px;\n background: #fff;\n box-shadow: inset 0 0 0 1px var(--line);\n}\n.bm-sidebar .bm-position-cell:hover:not(:disabled) {\n background: var(--accent-tint);\n}\n.bm-sidebar .bm-position-cell[aria-checked=\"true\"],\n.bm-sidebar .bm-position-cell[aria-checked=\"true\"]:hover:not(:disabled) {\n background: var(--accent);\n box-shadow: none;\n}\n.bm-sidebar .bm-position-cell:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.bm-slot,\n.bm-dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n width: 100%;\n min-height: 96px;\n padding: 14px;\n border: 1.5px dashed oklch(0.82 0.006 250);\n border-radius: 10px;\n background: var(--fill-soft);\n color: var(--ink-2);\n text-align: center;\n cursor: pointer;\n}\n.bm-sidebar .bm-slot:hover:not(:disabled),\n.bm-dropzone:hover {\n border-color: var(--accent);\n background: var(--accent-tint);\n}\n.bm-dropzone {\n min-height: 180px;\n position: relative;\n}\n.bm-dropzone:focus-within {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n.bm-dropzone-over {\n border-color: var(--accent);\n background: var(--accent-tint);\n}\n.bm-slot-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--ink);\n}\n.bm-slot-hint {\n font-size: 11px;\n color: var(--muted);\n}\n.bm-scrim {\n position: fixed;\n inset: 0;\n z-index: 7;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding: 10vh 16px 16px;\n background: oklch(0.2 0.01 255 / 0.4);\n}\n.bm-modal {\n display: flex;\n flex-direction: column;\n width: min(480px, 100%);\n max-height: min(560px, 80vh);\n overflow: hidden;\n padding: 20px 0 0;\n border-radius: 14px;\n background: #fff;\n box-shadow: var(--bm-shadow-dialog);\n}\n.bm-modal-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 0 20px 12px;\n}\n.bm-modal-head .bm-dialog-title {\n flex: none;\n}\n.bm-modal-head .bm-meta-tag {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-modal-head .bm-icon-btn {\n margin: -6px -8px -6px 0;\n}\n.bm-modal .bm-tabs {\n margin: 0 20px;\n padding: 3px;\n gap: 0;\n border: 0;\n border-radius: 9px;\n background: var(--bm-fill);\n overflow: visible;\n}\n.bm-modal .bm-tabs button {\n flex: 1;\n height: 36px;\n min-height: 36px;\n padding: 0 8px;\n border-radius: 7px;\n font-size: 13px;\n font-weight: 400;\n}\n.bm-modal .bm-tabs button:hover {\n background: oklch(1 0 0 / 0.5);\n}\n.bm-modal .bm-tabs button[aria-selected=\"true\"] {\n background: #fff;\n color: var(--ink);\n font-weight: 500;\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-modal-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 16px 20px 20px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.bm-library {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 10px;\n}\n.bm-library-item {\n position: relative;\n}\n.bm-library-pick {\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n min-height: 0;\n padding: 4px;\n border: 0;\n border-radius: 9px;\n background: var(--fill-soft);\n text-align: left;\n font-family: var(--mono);\n font-size: 9px;\n font-weight: 400;\n color: var(--muted);\n word-break: break-all;\n cursor: pointer;\n}\n.bm-library-pick:hover {\n background: var(--fill-hover);\n}\n.bm-library-pick img {\n width: 100%;\n aspect-ratio: 1 / 1;\n object-fit: cover;\n border-radius: 6px;\n background: var(--fill);\n}\n.bm-library-pick[aria-pressed=\"true\"] {\n box-shadow: 0 0 0 2px var(--accent);\n background: var(--accent-tint);\n}\n.bm-library-delete {\n position: absolute;\n top: 8px;\n right: 8px;\n width: 24px;\n height: 24px;\n min-height: 0;\n background: #fff;\n box-shadow: 0 1px 3px oklch(0.2 0.01 255 / 0.25);\n opacity: 0;\n}\n.bm-library-item:hover .bm-library-delete,\n.bm-library-delete:focus-visible {\n opacity: 1;\n}\n.bm-library-empty {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n}\n.bm-modal-confirm {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px 20px 16px;\n border-top: 1px solid var(--line-soft);\n background: var(--danger-tint);\n}\n.bm-modal-confirm .bm-note {\n color: var(--danger-ink);\n font-size: 13px;\n line-height: 1.5;\n}\n.bm-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n border: 0;\n white-space: nowrap;\n}\n.bm-popover-title {\n grid-column: 1 / -1;\n padding: 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--bm-ink);\n}\n.bm-popover-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0;\n}\n.bm-popover-head-wide {\n grid-column: 1 / -1;\n}\n.bm-popover[aria-label=\"Edit link\"],\n.bm-popover[aria-label=\"Add section\"][role=\"listbox\"] {\n z-index: 5;\n}\n.bm-popover :is(.bm-fmt-bold) {\n font-weight: 700;\n}\n.bm-fmt-bold {\n font-weight: 700;\n font-size: 13px;\n}\n.bm-fmt-italic {\n font-family: var(--serif);\n font-style: italic;\n font-size: 15px;\n}\n\n/* Edit link: Advanced row */\n.bm-advanced {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n.bm-popover button.bm-advanced-toggle {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-height: 32px;\n padding: 0 2px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--bm-label);\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n}\n.bm-popover button.bm-advanced-toggle:hover {\n background: transparent;\n color: var(--bm-ink);\n}\n.bm-advanced-toggle .bm-chevron {\n transition: transform 0.12s;\n}\n.bm-advanced-toggle[aria-expanded=\"true\"] .bm-chevron {\n transform: rotate(90deg);\n}\n.bm-advanced-summary {\n margin-left: auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--bm-muted);\n}\n\n/* SEO card and dialog */\n.bm-seo-card {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.bm-seo-badges {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.bm-seo-badge {\n padding: 2px 8px;\n border-radius: 999px;\n background: var(--fill-soft);\n color: var(--bm-label);\n font-family: var(--mono);\n font-size: 11px;\n}\n.bm-seo-edit,\n.bm-consent-edit {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n.bm-dialog.bm-seo {\n position: relative;\n width: min(560px, 100%);\n max-height: calc(100vh - 10vh - 32px);\n min-height: 0;\n}\n.bm-seo-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n min-height: 0;\n overflow-y: auto;\n padding: 2px 4px 2px 2px;\n}\n.bm-seo-json {\n min-height: 220px;\n white-space: pre;\n overflow: auto;\n tab-size: 2;\n}\n.bm-seo-json[aria-invalid=\"true\"] {\n border-color: var(--bm-danger);\n}\n.bm-seo-format {\n align-self: flex-start;\n}\n\n/* Cookie banner dialog */\n.bm-dialog.bm-consent {\n position: relative;\n width: min(520px, 100%);\n max-height: calc(100vh - 10vh - 32px);\n min-height: 0;\n}\n.bm-consent-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n min-height: 0;\n overflow-y: auto;\n padding: 2px 4px 2px 2px;\n}\n.bm-consent-preview {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--fill-soft);\n}\n.bm-consent-preview-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--bm-label);\n}\n.bm-consent-preview-text {\n margin: 0;\n font-size: 13px;\n line-height: 1.45;\n color: var(--bm-muted);\n overflow-wrap: anywhere;\n}\n.bm-consent-preview-link {\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n.bm-consent-preview-buttons {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.bm-consent-preview-buttons > span {\n padding: 5px 14px;\n border-radius: 999px;\n box-shadow: inset 0 0 0 1px var(--bm-border);\n font-size: 13px;\n font-weight: 500;\n color: var(--bm-label);\n}\n\n/* SEO preview, OG row, outline */\n.bm-serp {\n display: flex;\n flex-direction: column;\n gap: 3px;\n padding: 12px 14px;\n border-radius: 10px;\n background: var(--fill-soft);\n}\n.bm-serp-image {\n flex-direction: row;\n align-items: flex-start;\n gap: 12px;\n}\n.bm-serp-text {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n.bm-serp-thumb {\n flex: none;\n width: 64px;\n height: 64px;\n border-radius: 8px;\n object-fit: cover;\n background: var(--fill);\n}\n.bm-serp-title {\n font-size: 15px;\n font-weight: 500;\n color: oklch(0.42 0.12 260);\n}\n.bm-serp-url {\n font-family: var(--mono);\n font-size: 11px;\n color: oklch(0.45 0.08 145);\n}\n.bm-serp-desc {\n font-size: 12px;\n line-height: 1.45;\n color: oklch(0.45 0.01 255);\n}\n.bm-outline-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.bm-sidebar .bm-outline-row {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n min-height: 40px;\n padding: 0 10px;\n border-radius: 8px;\n background: transparent;\n text-align: left;\n font-size: 14px;\n}\n.bm-sidebar .bm-outline-row:hover:not(:disabled) {\n background: var(--fill-soft);\n}\n\n/* Section rows (Pages tab): grip, tone swatch, name over #anchor and variant, then actions. */\n.bm-srow {\n position: relative;\n display: flex;\n align-items: center;\n gap: 4px;\n min-height: 52px;\n padding: 6px 6px 6px 8px;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n}\n.bm-srow:hover {\n border-color: oklch(0.8 0.008 250);\n}\n.bm-srow-grip {\n flex: none;\n width: 16px;\n height: 32px;\n display: inline-grid;\n place-items: center;\n cursor: grab;\n touch-action: none;\n}\n.bm-srow-grip:active {\n cursor: grabbing;\n}\n.bm-srow .bm-outline-row {\n flex: 1;\n min-width: 0;\n width: auto;\n padding: 0 8px 0 4px;\n gap: 10px;\n}\n.bm-srow .bm-swatch {\n width: 10px;\n height: 10px;\n border-radius: 2px;\n}\n.bm-srow-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n.bm-srow-name {\n font-size: 14px;\n font-weight: 500;\n color: var(--bm-ink);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-srow-meta {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--bm-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-srow .bm-outline-meta {\n flex: none;\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-srow-btn {\n width: 32px;\n height: 32px;\n background: transparent;\n color: var(--bm-icon);\n border-radius: 7px;\n}\n.bm-srow-btn:disabled {\n opacity: 0.35;\n}\n.bm-sidebar .bm-srow-btn:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n.bm-sidebar .bm-srow-btn.bm-danger {\n color: var(--bm-danger-icon);\n}\n.bm-sidebar .bm-srow-btn.bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n}\n.bm-srow-sep {\n flex: none;\n width: 1px;\n height: 20px;\n margin: 0 2px;\n background: var(--bm-divider);\n}\n.bm-outline-n {\n width: 18px;\n font-family: var(--mono);\n font-size: 11px;\n color: oklch(0.55 0.01 255);\n}\n.bm-outline-label {\n flex: 1;\n min-width: 0;\n font-weight: 500;\n}\n.bm-outline-meta {\n font-family: var(--mono);\n font-size: 11px;\n font-weight: 400;\n color: var(--muted);\n}\n\n/* Navigation and footer link cards */\n.bm-nav-card {\n padding: 12px 12px 14px;\n gap: 10px;\n}\n.bm-nested {\n margin: 6px 0 0 16px;\n}\n.bm-nav-children {\n margin-top: -4px;\n}\n.bm-nav-head {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.bm-nav-head .bm-icon-btn,\n.bm-column-head .bm-icon-btn {\n background: var(--bm-fill);\n color: oklch(0.45 0.01 255);\n}\n.bm-nav-head .bm-icon-btn:hover:not(:disabled),\n.bm-column-head .bm-icon-btn:hover:not(:disabled) {\n background: var(--bm-fill-hover);\n color: var(--bm-ink);\n}\n.bm-sidebar .bm-nav-head .bm-icon-btn.bm-danger,\n.bm-sidebar .bm-column-head .bm-icon-btn.bm-danger {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-icon);\n}\n.bm-sidebar .bm-nav-label {\n flex: 1;\n min-width: 0;\n min-height: 32px;\n padding: 0 8px;\n border-color: transparent;\n font-weight: 500;\n}\n.bm-sidebar .bm-nav-label:hover {\n border-color: var(--line);\n}\n.bm-column {\n padding: 0;\n gap: 0;\n}\n.bm-column-head {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px;\n cursor: grab;\n}\n.bm-column-links > summary {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: 40px;\n padding: 0 12px;\n border-top: 1px solid var(--line-soft);\n font-size: 13px;\n font-weight: 500;\n color: var(--bm-label);\n cursor: pointer;\n list-style: none;\n}\n.bm-column-links > summary::-webkit-details-marker {\n display: none;\n}\n.bm-column-links > :not(summary) {\n margin: 10px 12px 0;\n}\n.bm-column-links > :last-child {\n margin-bottom: 12px;\n}\n\n/* Wordmark preview */\n.bm-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.bm-card-head .bm-label {\n flex: none;\n}\n.bm-combo {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n:is(.bm-sidebar, .bm-popover) .bm-combo-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n width: auto;\n max-width: 140px;\n min-height: 38px;\n padding: 0 10px 0 12px;\n border: 0;\n border-left: 1px solid var(--bm-border);\n border-radius: 0;\n background: var(--fill-soft);\n color: var(--ink-2);\n font-family: var(--mono);\n font-size: 12px;\n font-weight: 400;\n text-align: left;\n}\n:is(.bm-sidebar, .bm-popover) .bm-combo-trigger:hover:not(:disabled) {\n background: var(--fill-hover);\n}\n:is(.bm-sidebar, .bm-popover) .bm-combo-trigger[aria-expanded=\"true\"] {\n background: var(--accent-tint);\n color: var(--accent-hover);\n}\n/* One URL field: the text input and the page picker share a single border. */\n.bm-linkfield {\n display: flex;\n align-items: stretch;\n min-height: 40px;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n overflow: hidden;\n}\n.bm-linkfield:focus-within {\n border-color: var(--bm-primary);\n box-shadow: 0 0 0 3px var(--bm-primary-ring);\n}\n.bm-linkfield > input {\n flex: 1;\n min-width: 0;\n border: 0 !important;\n box-shadow: none !important;\n border-radius: 0;\n min-height: 38px;\n background: transparent;\n}\n.bm-linkfield .bm-combo {\n flex: none;\n max-width: 45%;\n}\n.bm-linkfield .bm-combo-trigger {\n height: 100%;\n}\n.bm-linkfield .bm-combo-trigger:focus-visible {\n outline-offset: -2px;\n}\n.bm-combo-trigger > span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bm-combo-trigger .bm-combo-custom {\n color: var(--muted);\n}\n.bm-combo-panel {\n position: fixed;\n z-index: 6;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n background: #fff;\n box-shadow: 0 6px 18px oklch(0.2 0.02 255 / 0.1);\n}\n.bm-combo-list {\n max-height: 200px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n}\n.bm-combo-group {\n margin: 6px 6px 2px;\n font-family: var(--mono);\n font-size: 10px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--muted);\n}\n.bm-combo-option {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 10px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 13px;\n color: var(--ink);\n cursor: pointer;\n}\n.bm-combo-option[aria-selected=\"true\"] {\n font-weight: 600;\n color: var(--accent-hover);\n}\n.bm-combo-active {\n background: var(--fill);\n}\n.bm-combo-value {\n flex: none;\n max-width: 50%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--mono);\n font-size: 11px;\n color: var(--muted);\n}\n.bm-combo-empty {\n margin: 0;\n padding: 8px;\n font-size: 12px;\n color: var(--muted);\n}\n.bm-format {\n margin-top: -4px;\n}\n.bm-sidebar .bm-format button[aria-pressed=\"true\"] {\n background: #fff;\n color: var(--ink);\n box-shadow: var(--bm-shadow-segment-on);\n}\n.bm-wordmark {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n padding: 12px 14px;\n border-radius: 10px;\n background: var(--bm-fill-soft);\n}\n.bm-wordmark-name {\n font-size: 24px;\n font-weight: 600;\n letter-spacing: -0.03em;\n}\n.bm-alert-notice {\n flex-direction: row;\n align-items: flex-start;\n gap: 8px;\n color: var(--warn-ink);\n}\n.bm-alert-notice .bm-icon {\n margin-top: 2px;\n flex: none;\n}\n\n/*\n * Button system. Three variants, one danger modifier, one rule set.\n * secondary (default): neutral fill, ink text.\n * .bm-primary: the one main action of a surface. Solid accent, white text (AA).\n * .bm-tertiary: low emphasis text button (Cancel, Reset). No fill, no underline, grey fill on hover.\n * .bm-danger: modifier. primary = solid red, secondary = red text, tertiary = red text.\n * The scope list gives every rule enough specificity to beat the per-surface defaults above,\n * so the hover state of one variant can never fall back to the secondary fill.\n */\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button:where(.bm-primary, .bm-tertiary, .bm-danger):not(.bm-icon-btn, .bm-save) {\n transition:\n background-color 0.12s,\n color 0.12s;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary {\n background: var(--bm-primary);\n color: #fff;\n box-shadow: none;\n font-weight: 600;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary:hover:not(:disabled) {\n background: var(--bm-primary-hover);\n color: #fff;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary.bm-danger {\n background: var(--bm-danger);\n color: #fff;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-primary.bm-danger:hover:not(:disabled) {\n background: var(--danger-hover);\n color: #fff;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-danger:not(.bm-primary, .bm-tertiary, .bm-icon-btn) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-danger:not(.bm-primary, .bm-tertiary, .bm-icon-btn):hover:not(:disabled) {\n background: oklch(0.93 0.04 25);\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary {\n min-height: 32px;\n padding: 0 10px;\n border-radius: 8px;\n background: transparent;\n color: var(--bm-label);\n font-weight: 400;\n box-shadow: none;\n text-decoration: none;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal) button.bm-tertiary {\n min-height: 38px;\n font-size: 14px;\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary:hover:not(:disabled) {\n background: var(--bm-fill);\n color: var(--bm-ink);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary.bm-danger {\n background: transparent;\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button.bm-tertiary.bm-danger:hover:not(:disabled) {\n background: var(--bm-danger-soft);\n color: var(--bm-danger-text);\n}\n:is(.bm-dialog, .bm-popover, .bm-modal, .bm-sidebar) button:disabled {\n opacity: 0.5;\n cursor: default;\n}\n.bm-save:hover:not(:disabled) {\n background: var(--accent-hover);\n color: #fff;\n}\n.bm-sidebar .bm-save:hover:not(:disabled) {\n background: var(--accent-hover);\n color: #fff;\n}\n.bm-popover .bm-actions-remove,\n.bm-dialog .bm-actions-remove {\n margin-right: auto;\n}\n.bm-modal :where(button:not([role=\"tab\"], .bm-library-pick, .bm-icon-btn, .bm-tertiary)) {\n min-height: 38px;\n padding: 0 16px;\n border: 0;\n border-radius: 8px;\n background: var(--fill);\n color: var(--ink);\n font-size: 14px;\n font-weight: 400;\n}\n.bm-modal :where(button:not([role=\"tab\"], .bm-library-pick, .bm-icon-btn, .bm-tertiary)):hover:not(:disabled) {\n background: var(--fill-hover);\n}\n.bm-modal .bm-dropzone {\n font-family: var(--sans);\n}\n\n/* Design tab */\n.bm-colorrow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.bm-colorpick {\n flex: none;\n width: 40px !important;\n height: 40px;\n min-height: 40px !important;\n padding: 2px !important;\n border: 1px solid var(--bm-border);\n border-radius: 8px;\n background: #fff;\n cursor: pointer;\n}\n.bm-colorhex {\n flex: 1;\n min-width: 0;\n font-family: var(--mono);\n font-size: 13px;\n text-transform: lowercase;\n}\n.bm-colorhex[aria-invalid=\"true\"] {\n border-color: var(--bm-danger);\n}\n.bm-overrides {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--bm-border);\n border-radius: 10px;\n overflow: hidden;\n}\n.bm-override-row {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px 8px 12px;\n}\n.bm-override-row + .bm-override-row {\n border-top: 1px solid var(--bm-divider);\n}\n.bm-override-label {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: 6px;\n font-size: 13px;\n font-weight: 500;\n color: var(--bm-label);\n}\n.bm-override-label .bm-meta-tag {\n font-size: 10px;\n}\n.bm-override-row .bm-colorpick {\n width: 32px !important;\n height: 32px;\n min-height: 32px !important;\n padding: 1px !important;\n border-radius: 7px;\n}\n.bm-override-row .bm-colorhex {\n flex: none;\n width: 104px;\n min-height: 36px;\n padding: 0 10px;\n}\n.bm-tone-matrix {\n display: grid;\n grid-template-columns: 60px minmax(0, 1fr) minmax(0, 1fr);\n gap: 8px;\n align-items: stretch;\n}\n.bm-tone-pick {\n border: 0;\n text-align: left;\n font: inherit;\n cursor: pointer;\n}\n.bm-tone-cell[aria-pressed=\"true\"] {\n outline: 2px solid var(--bm-primary);\n outline-offset: 0;\n}\n.bm-tone-head {\n font-family: var(--mono);\n font-size: 10px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--muted);\n}\n.bm-tone-name {\n align-self: center;\n font-size: 12px;\n font-weight: 500;\n color: var(--ink-2);\n}\n.bm-tone-cell {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n min-width: 0;\n min-height: 46px;\n padding: 0 10px;\n border-radius: 8px;\n overflow: hidden;\n white-space: nowrap;\n}\n.bm-tone-aa {\n flex: none;\n font-size: 16px;\n font-weight: 600;\n}\n.bm-tone-muted {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 11px;\n}\n.bm-tone-chip {\n flex: none;\n padding: 2px 6px;\n border-radius: 5px;\n font-size: 10px;\n font-weight: 600;\n}\n.bm-tone-link {\n flex: none;\n font-size: 11px;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.bm-contrast-list {\n margin: 6px 0 0;\n padding-left: 16px;\n font-family: var(--mono);\n font-size: 11px;\n color: var(--warn-ink);\n}\n.bm-range {\n flex: 1;\n min-width: 0;\n min-height: 28px;\n accent-color: var(--accent);\n cursor: pointer;\n}\n/* Preview: the only editor UI left on screen. */\n.bm-exit-preview {\n position: fixed;\n z-index: 7;\n right: 16px;\n bottom: 16px;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 40px;\n padding: 0 16px;\n border: 0;\n border-radius: 999px;\n background: var(--ink);\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n box-shadow: 0 10px 30px oklch(0.2 0.02 255 / 0.3);\n}\n.bm-exit-preview:hover {\n background: oklch(0.28 0.012 255);\n}\n.bm-exit-preview:focus-visible {\n outline-color: oklch(0.82 0.14 145);\n outline-offset: 3px;\n}\n.bm-srow-add {\n display: flex;\n justify-content: flex-end;\n padding-top: 6px;\n}\n.bm-sidebar .bm-add-section {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 32px;\n padding: 0 12px;\n border: 0;\n border-radius: 8px;\n background: var(--bm-primary);\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n}\n.bm-sidebar .bm-add-section:hover {\n background: var(--bm-primary-hover);\n}\n";
19712
19969
  //#endregion
19713
19970
  //#region src/ui/styles.ts
19714
19971
  function boxStyle(rect, offset = 0) {
@@ -21055,7 +21312,7 @@ function siteOptionControl(site, option, onField) {
21055
21312
  onChange: (value) => onField(option.name, value)
21056
21313
  }, option.name);
21057
21314
  }
21058
- function SiteForm({ site, options, images, onField, onOptional, onMarks, onUploaded, onDeleted }) {
21315
+ function SiteForm({ site, options, images, onField, onOptional, onConsentEnabled, onEditConsent, onMarks, onUploaded, onDeleted }) {
21059
21316
  const logo = getAt(site, "favicon") ?? getAt(site, "logo");
21060
21317
  const groupOf = (option) => SITE_GROUPS.find((group) => option.name.startsWith(group.prefix));
21061
21318
  const shown = options.filter((option) => !option.name.startsWith("footer.") && !option.name.startsWith("header.") && option.name !== "theme.mode");
@@ -21162,10 +21419,16 @@ function SiteForm({ site, options, images, onField, onOptional, onMarks, onUploa
21162
21419
  }),
21163
21420
  /* @__PURE__ */ jsx("p", {
21164
21421
  class: "bm-hint",
21165
- children: "Runs on your live site only: not while you edit, and not on Vercel or Netlify previews. Most analytics tools need a consent banner for visitors in the EU."
21422
+ children: "Runs on your live site only: not while you edit, and not on Vercel or Netlify previews."
21166
21423
  })
21167
21424
  ]
21168
21425
  }),
21426
+ /* @__PURE__ */ jsx(ConsentGroup, {
21427
+ enabled: consentEnabled(site),
21428
+ snippets: hasAnalyticsSnippet(site),
21429
+ onEnabled: onConsentEnabled,
21430
+ onEdit: onEditConsent
21431
+ }),
21169
21432
  SITE_GROUPS.map((group) => {
21170
21433
  const items = shown.filter((option) => groupOf(option) === group);
21171
21434
  if (items.length === 0) return null;
@@ -21206,6 +21469,49 @@ function SiteGroup({ title, items, control, extra }) {
21206
21469
  ]
21207
21470
  });
21208
21471
  }
21472
+ /** The cookie banner: a switch here, its text in a dialog. */
21473
+ function ConsentGroup({ enabled, snippets, onEnabled, onEdit }) {
21474
+ return /* @__PURE__ */ jsxs("div", {
21475
+ class: "bm-stack",
21476
+ children: [
21477
+ /* @__PURE__ */ jsx("p", {
21478
+ class: "bm-group",
21479
+ children: "Cookie banner"
21480
+ }),
21481
+ /* @__PURE__ */ jsxs("label", {
21482
+ class: "bm-switch-row",
21483
+ children: [/* @__PURE__ */ jsx("span", {
21484
+ class: "bm-switch-text",
21485
+ children: /* @__PURE__ */ jsxs("span", {
21486
+ class: "bm-switch-title",
21487
+ children: ["Ask before analytics runs", /* @__PURE__ */ jsx(Info, {
21488
+ label: "About the cookie banner",
21489
+ text: "Visitors in the EU and UK must agree before analytics cookies are set. With the banner on, nothing from the snippets loads until they accept. Google tags also get Consent Mode v2 signals."
21490
+ })]
21491
+ })
21492
+ }), /* @__PURE__ */ jsx("input", {
21493
+ type: "checkbox",
21494
+ role: "switch",
21495
+ checked: enabled,
21496
+ onChange: (event) => onEnabled(event.currentTarget.checked)
21497
+ })]
21498
+ }),
21499
+ /* @__PURE__ */ jsx("p", {
21500
+ class: "bm-hint",
21501
+ children: !enabled ? "Off. Your snippets run for every visitor from the first page, EU visitors included." : snippets ? "On. Your snippets wait until the visitor accepts. The banner also shows while you edit, with analytics off." : "On. It appears once you add an analytics snippet above."
21502
+ }),
21503
+ /* @__PURE__ */ jsxs("button", {
21504
+ type: "button",
21505
+ class: "bm-tertiary bm-consent-edit",
21506
+ onClick: onEdit,
21507
+ children: [/* @__PURE__ */ jsx(Icon, {
21508
+ name: "settings",
21509
+ size: 14
21510
+ }), "Edit banner"]
21511
+ })
21512
+ ]
21513
+ });
21514
+ }
21209
21515
  //#endregion
21210
21516
  //#region src/ui/forms/footer-form.tsx
21211
21517
  /** Footer tab: layout, text, and the columns with their links. */
@@ -22104,7 +22410,7 @@ function DesignPanel({ site }) {
22104
22410
  });
22105
22411
  }
22106
22412
  function SitePanel({ site, catalog }) {
22107
- const { doc, edits } = useEditor();
22413
+ const { doc, edits, ui } = useEditor();
22108
22414
  return /* @__PURE__ */ jsx(SiteForm, {
22109
22415
  site,
22110
22416
  options: catalog.siteOptions,
@@ -22116,6 +22422,14 @@ function SitePanel({ site, catalog }) {
22116
22422
  const node = getAt(doc.site.peek(), "analytics");
22117
22423
  if (typeof node === "object" && node !== null && Object.keys(node).length === 0) edits.writeOrClear("analytics", "");
22118
22424
  },
22425
+ onConsentEnabled: (enabled) => {
22426
+ edits.writeField("consent.enabled", enabled ? void 0 : false);
22427
+ const node = getAt(doc.site.peek(), "consent");
22428
+ if (typeof node === "object" && node !== null && Object.keys(node).length === 0) edits.writeOrClear("consent", "");
22429
+ },
22430
+ onEditConsent: () => {
22431
+ ui.dialog.value = { kind: "consent" };
22432
+ },
22119
22433
  onMarks: edits.applyMarksAt,
22120
22434
  onUploaded: doc.addImage,
22121
22435
  onDeleted: doc.dropImage