@bendyline/squisq 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/{Doc-ylqWKDc_.d.ts → Doc-DynJleo-.d.ts} +159 -2
  2. package/dist/{ImageEditDoc-D828IXJ1.d.ts → ImageEditDoc-Ca4Tr9uN.d.ts} +1 -1
  3. package/dist/{chunk-PXLVXTLW.js → chunk-ILWDXLUK.js} +24 -6
  4. package/dist/chunk-ILWDXLUK.js.map +1 -0
  5. package/dist/{chunk-6PJRB2CF.js → chunk-JHZWYRSW.js} +570 -2
  6. package/dist/chunk-JHZWYRSW.js.map +1 -0
  7. package/dist/{chunk-GF3BVNLU.js → chunk-JI77MGAK.js} +195 -27
  8. package/dist/chunk-JI77MGAK.js.map +1 -0
  9. package/dist/{chunk-QVANWDPH.js → chunk-OTKVFVL6.js} +1403 -41
  10. package/dist/chunk-OTKVFVL6.js.map +1 -0
  11. package/dist/{chunk-LYNJEOAC.js → chunk-QUUPYOSP.js} +8 -2
  12. package/dist/chunk-QUUPYOSP.js.map +1 -0
  13. package/dist/chunk-VWCJ2WXC.js +215 -0
  14. package/dist/chunk-VWCJ2WXC.js.map +1 -0
  15. package/dist/{chunk-QTSJOY54.js → chunk-VYFRI7R6.js} +2 -2
  16. package/dist/{chunk-T3TI7GSZ.js → chunk-XNLB57UD.js} +2 -2
  17. package/dist/doc/index.d.ts +144 -5
  18. package/dist/doc/index.js +24 -4
  19. package/dist/generate/index.d.ts +1 -1
  20. package/dist/imageEdit/index.d.ts +3 -3
  21. package/dist/index.d.ts +6 -5
  22. package/dist/index.js +66 -8
  23. package/dist/jsonForm/index.d.ts +1 -1
  24. package/dist/jsonForm/index.js +4 -4
  25. package/dist/materializePageSection-DDzubQXo.d.ts +223 -0
  26. package/dist/narration/index.d.ts +1 -1
  27. package/dist/narration/index.js +3 -3
  28. package/dist/schemas/index.d.ts +30 -5
  29. package/dist/schemas/index.js +41 -3
  30. package/dist/{themeLibrary-RjVgLpUi.d.ts → themeLibrary-B72m0W1y.d.ts} +1 -1
  31. package/dist/transform/index.d.ts +8 -9
  32. package/dist/transform/index.js +1 -1
  33. package/package.json +1 -1
  34. package/src/__tests__/customThemesFrontmatter.test.ts +1 -0
  35. package/src/__tests__/markdown.test.ts +13 -4
  36. package/src/__tests__/markdownSanitize.test.ts +7 -5
  37. package/src/__tests__/materializeBlockLayers.test.ts +32 -0
  38. package/src/__tests__/materializePageSections.test.ts +404 -0
  39. package/src/__tests__/pageStyle.test.ts +258 -0
  40. package/src/__tests__/templateAnnotationParse.test.ts +13 -0
  41. package/src/doc/index.ts +34 -0
  42. package/src/doc/markdownToDoc.ts +3 -1
  43. package/src/doc/materializeBlockLayers.ts +170 -9
  44. package/src/doc/page/PageSection.ts +174 -0
  45. package/src/doc/page/materializePageSection.ts +616 -0
  46. package/src/doc/page/resolvePageBlock.ts +108 -0
  47. package/src/doc/page/sectionExtractors.ts +466 -0
  48. package/src/doc/pageCss.ts +628 -0
  49. package/src/doc/templateInputs.ts +1 -0
  50. package/src/doc/templates/__tests__/listBlock.test.ts +64 -0
  51. package/src/doc/templates/listBlock.ts +88 -30
  52. package/src/schemas/Doc.ts +22 -1
  53. package/src/schemas/PageStyle.ts +213 -0
  54. package/src/schemas/Theme.ts +7 -0
  55. package/src/schemas/index.ts +2 -0
  56. package/src/schemas/pageStyleDefaults.ts +204 -0
  57. package/src/schemas/themeCompile.ts +7 -0
  58. package/src/schemas/themeValidator.ts +183 -0
  59. package/src/schemas/themes/bold.json +29 -0
  60. package/src/schemas/themes/cinematic.json +32 -0
  61. package/src/schemas/themes/documentary.json +29 -0
  62. package/src/schemas/themes/gezellig.json +31 -1
  63. package/src/schemas/themes/magazine.json +37 -0
  64. package/src/schemas/themes/minimalist.json +29 -0
  65. package/src/schemas/themes/morning-light.json +32 -0
  66. package/src/schemas/themes/standard-dark.json +24 -0
  67. package/src/schemas/themes/standard.json +24 -0
  68. package/src/schemas/themes/tech-dark.json +42 -0
  69. package/src/schemas/themes/warm-earth.json +24 -0
  70. package/src/transform/registry.ts +19 -0
  71. package/src/transform/styles/dataDriven.ts +1 -0
  72. package/src/transform/styles/documentary.ts +1 -0
  73. package/src/transform/styles/magazine.ts +1 -0
  74. package/src/transform/styles/minimal.ts +1 -0
  75. package/src/transform/styles/narrative.ts +1 -0
  76. package/src/transform/types.ts +7 -0
  77. package/dist/chunk-6PJRB2CF.js.map +0 -1
  78. package/dist/chunk-FVJUUTEM.js +0 -74
  79. package/dist/chunk-FVJUUTEM.js.map +0 -1
  80. package/dist/chunk-GF3BVNLU.js.map +0 -1
  81. package/dist/chunk-LYNJEOAC.js.map +0 -1
  82. package/dist/chunk-PXLVXTLW.js.map +0 -1
  83. package/dist/chunk-QVANWDPH.js.map +0 -1
  84. /package/dist/{chunk-QTSJOY54.js.map → chunk-VYFRI7R6.js.map} +0 -0
  85. /package/dist/{chunk-T3TI7GSZ.js.map → chunk-XNLB57UD.js.map} +0 -0
@@ -2,11 +2,14 @@ import {
2
2
  SHAPE_NAMES,
3
3
  TEMPLATE_ALIASES,
4
4
  buildNarrationScript,
5
+ coerceTemplateParams,
5
6
  deriveTemplateInputs,
7
+ extractBodyPlainText,
6
8
  flattenBlocks,
7
9
  flattenRenderableBlocks,
8
10
  getBlockBodyText,
9
11
  getPinnedBlockMeta,
12
+ isContainerTemplate,
10
13
  isDataFence,
11
14
  isShapeName,
12
15
  lintTemplateParams,
@@ -21,7 +24,7 @@ import {
21
24
  templateRegistry,
22
25
  writeCustomTemplatesToFrontmatter,
23
26
  writeCustomThemesToFrontmatter
24
- } from "./chunk-GF3BVNLU.js";
27
+ } from "./chunk-JI77MGAK.js";
25
28
  import {
26
29
  ASCII_TREE_VOCAB,
27
30
  ASCII_VOCAB,
@@ -36,14 +39,21 @@ import {
36
39
  traceBoxes
37
40
  } from "./chunk-5UYI3RJB.js";
38
41
  import {
42
+ defaultPageStyle,
39
43
  resolveMediaSchedule
40
- } from "./chunk-FVJUUTEM.js";
44
+ } from "./chunk-VWCJ2WXC.js";
41
45
  import {
46
+ DEFAULT_THEME,
42
47
  FRONTMATTER_CUSTOM_TEMPLATES_KEY,
43
48
  FRONTMATTER_CUSTOM_THEMES_KEY,
44
49
  hexHueDegrees,
50
+ resolveFontFamily,
45
51
  resolveTheme
46
- } from "./chunk-6PJRB2CF.js";
52
+ } from "./chunk-JHZWYRSW.js";
53
+ import {
54
+ VIEWPORT_PRESETS,
55
+ isTemplateBlock
56
+ } from "./chunk-5J4HKRJF.js";
47
57
  import {
48
58
  parseMarkdown
49
59
  } from "./chunk-66QO7XFB.js";
@@ -327,9 +337,9 @@ function docToMarkdown(doc) {
327
337
  const homelessDocMedia = [];
328
338
  for (const clip of doc.documentMedia ?? []) {
329
339
  if (clip.origin && blockIds.has(clip.origin.blockId)) {
330
- const list = docMediaByBlock.get(clip.origin.blockId) ?? [];
331
- list.push(clip);
332
- docMediaByBlock.set(clip.origin.blockId, list);
340
+ const list2 = docMediaByBlock.get(clip.origin.blockId) ?? [];
341
+ list2.push(clip);
342
+ docMediaByBlock.set(clip.origin.blockId, list2);
333
343
  } else {
334
344
  homelessDocMedia.push(clip);
335
345
  }
@@ -479,16 +489,1358 @@ function resolveThemeForDoc(doc, explicitId, registry) {
479
489
  return resolveTheme(id, registry);
480
490
  }
481
491
 
492
+ // src/doc/page/resolvePageBlock.ts
493
+ function isTemplatedPageBlock(block) {
494
+ if (block.sourceHeading?.templateAnnotation?.template) return true;
495
+ if (block.autoTemplate && block.template) return true;
496
+ return !block.sourceHeading && isTemplateBlock(block);
497
+ }
498
+ function templatedName(block) {
499
+ return block.sourceHeading?.templateAnnotation?.template ?? block.template;
500
+ }
501
+ function resolvePageBlock(block) {
502
+ if (!isTemplatedPageBlock(block)) return { templated: false };
503
+ const annotation = block.sourceHeading?.templateAnnotation;
504
+ const rawName = templatedName(block) ?? "sectionHeader";
505
+ const templateName = resolveTemplateName(rawName);
506
+ const rawParams = {
507
+ ...annotation?.params ?? {},
508
+ ...block.templateOverrides ?? {}
509
+ };
510
+ const coercedParams = coerceTemplateParams(rawName, rawParams).input;
511
+ let base;
512
+ if (annotation) {
513
+ const headingText = extractPlainText(block.sourceHeading);
514
+ base = {
515
+ id: block.id,
516
+ template: rawName,
517
+ startTime: 0,
518
+ duration: 1,
519
+ audioSegment: 0,
520
+ title: headingText,
521
+ contents: block.contents,
522
+ children: block.children,
523
+ ...deriveTemplateInputs(rawName, headingText, block.contents, {
524
+ placeholders: true
525
+ }) ?? {}
526
+ };
527
+ } else {
528
+ base = {
529
+ ...block,
530
+ startTime: block.startTime ?? 0,
531
+ duration: block.duration ?? 1,
532
+ audioSegment: block.audioSegment ?? 0,
533
+ template: rawName
534
+ };
535
+ }
536
+ const templateBlock = {
537
+ ...base,
538
+ ...block.templateData ?? {},
539
+ ...coercedParams
540
+ };
541
+ return { templated: true, templateName, templateBlock };
542
+ }
543
+
544
+ // src/doc/page/sectionExtractors.ts
545
+ function bodyRichText(input) {
546
+ const contents = input.contents;
547
+ if (!contents || contents.length === 0) return void 0;
548
+ const text = contents.map((node) => extractPlainText(node)).join("\n").trim();
549
+ return text ? { text, markdown: contents } : void 0;
550
+ }
551
+ function accentImageMedia(accent) {
552
+ if (!accent?.src) return void 0;
553
+ return {
554
+ type: "image",
555
+ src: accent.src,
556
+ alt: accent.alt ?? "",
557
+ credit: accent.credit,
558
+ license: accent.license
559
+ };
560
+ }
561
+ function canvasDraft(spatial, ctx, block) {
562
+ return {
563
+ kind: "canvas-embed",
564
+ variant: spatial,
565
+ slots: {
566
+ media: {
567
+ type: "canvas",
568
+ spatial,
569
+ block: block ?? ctx.block,
570
+ aspect: { width: ctx.viewport.width, height: ctx.viewport.height }
571
+ }
572
+ }
573
+ };
574
+ }
575
+ var title = (input) => {
576
+ const t = input;
577
+ const contents = input.contents;
578
+ const firstParagraph = contents?.find((node) => node.type === "paragraph");
579
+ const subtitle = t.subtitle ?? (firstParagraph ? extractPlainText(firstParagraph) : void 0);
580
+ return {
581
+ kind: "hero",
582
+ variant: "title",
583
+ slots: { title: t.title, subtitle },
584
+ emphasis: "lead",
585
+ hints: t.backgroundColor ? { backgroundColor: t.backgroundColor } : void 0
586
+ };
587
+ };
588
+ var sectionHeader = (input) => {
589
+ const s = input;
590
+ const media = s.imageSrc ? { type: "image", src: s.imageSrc, alt: s.imageAlt ?? "" } : void 0;
591
+ return {
592
+ kind: "banner",
593
+ slots: { title: s.title, media },
594
+ colorScheme: s.colorScheme,
595
+ mediaBackground: !!s.imageSrc
596
+ };
597
+ };
598
+ var statHighlight = (input) => {
599
+ const s = input;
600
+ return {
601
+ kind: "stat-band",
602
+ variant: "single",
603
+ slots: {
604
+ items: [{ value: s.stat, title: s.description, body: s.detail }],
605
+ media: accentImageMedia(s.accentImage)
606
+ },
607
+ emphasis: "strong",
608
+ colorScheme: s.colorScheme
609
+ };
610
+ };
611
+ var quote = (input) => {
612
+ const q = input;
613
+ return {
614
+ kind: "quote-band",
615
+ variant: "plain",
616
+ slots: {
617
+ body: { text: q.quote ?? "" },
618
+ attribution: q.attribution,
619
+ media: accentImageMedia(q.accentImage)
620
+ }
621
+ };
622
+ };
623
+ var factCard = (input) => {
624
+ const f = input;
625
+ return {
626
+ kind: "callout",
627
+ variant: "fact",
628
+ slots: {
629
+ title: f.fact,
630
+ body: { text: f.explanation ?? "" },
631
+ meta: f.source,
632
+ media: accentImageMedia(f.accentImage)
633
+ }
634
+ };
635
+ };
636
+ var twoColumn = (input) => {
637
+ const t = input;
638
+ return {
639
+ kind: "card-grid",
640
+ variant: "two-column",
641
+ slots: {
642
+ title: t.header,
643
+ items: [
644
+ { title: t.left?.label, body: t.left?.sublabel, accentScheme: t.leftColor },
645
+ { title: t.right?.label, body: t.right?.sublabel, accentScheme: t.rightColor }
646
+ ]
647
+ }
648
+ };
649
+ };
650
+ var dateEvent = (input) => {
651
+ const d = input;
652
+ return {
653
+ kind: "timeline-rail",
654
+ slots: {
655
+ milestone: {
656
+ date: d.date ?? "",
657
+ description: d.description ?? "",
658
+ footer: d.footer,
659
+ mood: d.mood
660
+ },
661
+ media: accentImageMedia(d.accentImage)
662
+ }
663
+ };
664
+ };
665
+ var imageWithCaption = (input) => {
666
+ const i = input;
667
+ const media = {
668
+ type: "image",
669
+ src: i.imageSrc,
670
+ alt: i.imageAlt ?? "",
671
+ credit: i.imageCredit,
672
+ license: i.imageLicense
673
+ };
674
+ if (i.isTitle) {
675
+ return {
676
+ kind: "hero",
677
+ variant: "media",
678
+ slots: { title: i.caption, subtitle: i.subtitle, media },
679
+ emphasis: "lead",
680
+ mediaBackground: true
681
+ };
682
+ }
683
+ return {
684
+ kind: "media-figure",
685
+ variant: "image",
686
+ slots: { media, caption: i.caption }
687
+ };
688
+ };
689
+ function featureDraft(input, side) {
690
+ return {
691
+ kind: "feature-split",
692
+ variant: side === "left" ? "media-left" : "media-right",
693
+ slots: {
694
+ title: input.title,
695
+ body: input.body ? { text: input.body } : void 0,
696
+ media: {
697
+ type: "image",
698
+ src: input.imageSrc,
699
+ alt: input.imageAlt ?? "",
700
+ width: input.imageWidth,
701
+ height: input.imageHeight
702
+ }
703
+ }
704
+ };
705
+ }
706
+ var leftFeature = (input) => featureDraft(input, "left");
707
+ var rightFeature = (input) => featureDraft(input, "right");
708
+ var fullBleedQuote = (input) => {
709
+ const f = input;
710
+ return {
711
+ kind: "quote-band",
712
+ variant: "display",
713
+ slots: { body: { text: f.text ?? "" } },
714
+ emphasis: "strong",
715
+ colorScheme: f.colorScheme
716
+ };
717
+ };
718
+ var list = (input) => {
719
+ const l = input;
720
+ return {
721
+ kind: "item-list",
722
+ slots: {
723
+ title: l.title,
724
+ items: (l.items ?? []).map((item) => ({ body: item })),
725
+ media: accentImageMedia(l.accentImage)
726
+ },
727
+ colorScheme: l.colorScheme
728
+ };
729
+ };
730
+ var photoGrid = (input) => {
731
+ const p = input;
732
+ const images = p.images ?? [];
733
+ const fallback = images.length === 0 ? {
734
+ title: input.title,
735
+ body: bodyRichText(input)
736
+ } : void 0;
737
+ return {
738
+ kind: "gallery",
739
+ slots: {
740
+ ...fallback,
741
+ caption: p.caption,
742
+ items: images.map((img) => ({
743
+ media: {
744
+ type: "image",
745
+ src: img.src,
746
+ alt: img.alt ?? "",
747
+ credit: img.credit,
748
+ license: img.license
749
+ }
750
+ }))
751
+ }
752
+ };
753
+ };
754
+ var definitionCard = (input) => {
755
+ const d = input;
756
+ return {
757
+ kind: "callout",
758
+ variant: "definition",
759
+ slots: {
760
+ title: d.term,
761
+ body: { text: d.definition ?? "" },
762
+ meta: d.origin,
763
+ media: accentImageMedia(d.accentImage)
764
+ },
765
+ colorScheme: d.colorScheme
766
+ };
767
+ };
768
+ var comparisonBar = (input) => {
769
+ const c = input;
770
+ return {
771
+ kind: "stat-band",
772
+ variant: "comparison",
773
+ slots: {
774
+ items: [
775
+ { title: c.leftLabel, value: c.leftValue },
776
+ { title: c.rightLabel, value: c.rightValue }
777
+ ],
778
+ meta: c.unit
779
+ },
780
+ emphasis: "strong",
781
+ colorScheme: c.colorScheme
782
+ };
783
+ };
784
+ var pullQuote = (input) => {
785
+ const p = input;
786
+ const bg = p.backgroundImage;
787
+ return {
788
+ kind: "quote-band",
789
+ variant: "full-bleed",
790
+ slots: {
791
+ body: { text: p.text ?? "" },
792
+ attribution: p.attribution,
793
+ media: bg?.src ? { type: "image", src: bg.src, alt: bg.alt ?? "", credit: bg.credit, license: bg.license } : void 0
794
+ },
795
+ emphasis: "strong",
796
+ mediaBackground: !!bg?.src
797
+ };
798
+ };
799
+ var videoWithCaption = (input) => {
800
+ const v = input;
801
+ return {
802
+ kind: "media-figure",
803
+ variant: "video",
804
+ slots: {
805
+ media: {
806
+ type: "video",
807
+ src: v.videoSrc,
808
+ posterSrc: v.posterSrc,
809
+ alt: v.videoAlt ?? "",
810
+ clipStart: v.clipStart,
811
+ clipEnd: v.clipEnd,
812
+ credit: v.videoCredit,
813
+ license: v.videoLicense
814
+ },
815
+ caption: v.caption
816
+ }
817
+ };
818
+ };
819
+ var videoPullQuote = (input) => {
820
+ const v = input;
821
+ const bg = v.backgroundVideo;
822
+ return {
823
+ kind: "quote-band",
824
+ variant: "full-bleed",
825
+ slots: {
826
+ body: { text: v.text ?? "" },
827
+ attribution: v.attribution,
828
+ media: bg?.src ? {
829
+ type: "video",
830
+ src: bg.src,
831
+ posterSrc: bg.posterSrc,
832
+ alt: bg.alt ?? "",
833
+ clipStart: bg.clipStart,
834
+ clipEnd: bg.clipEnd,
835
+ credit: bg.credit,
836
+ license: bg.license
837
+ } : void 0
838
+ },
839
+ emphasis: "strong",
840
+ mediaBackground: !!bg?.src
841
+ };
842
+ };
843
+ var dataTable = (input) => {
844
+ const d = input;
845
+ return {
846
+ kind: "table-section",
847
+ slots: {
848
+ title: d.title,
849
+ table: { headers: d.headers ?? [], rows: d.rows ?? [], align: d.align }
850
+ },
851
+ colorScheme: d.colorScheme
852
+ };
853
+ };
854
+ var diagram = (input, ctx) => canvasDraft("diagram", ctx, input);
855
+ var tree = (input, ctx) => canvasDraft("tree", ctx, input);
856
+ var timeline = (input, ctx) => canvasDraft("timeline", ctx, input);
857
+ var map = (input, ctx) => canvasDraft("map", ctx, input);
858
+ var drawing = (input, ctx) => canvasDraft("drawing", ctx, input);
859
+ var layout = (input, ctx) => canvasDraft("layout", ctx, input);
860
+ var sectionExtractors = {
861
+ title,
862
+ sectionHeader,
863
+ statHighlight,
864
+ quote,
865
+ factCard,
866
+ twoColumn,
867
+ dateEvent,
868
+ imageWithCaption,
869
+ leftFeature,
870
+ rightFeature,
871
+ map,
872
+ fullBleedQuote,
873
+ list,
874
+ photoGrid,
875
+ definitionCard,
876
+ comparisonBar,
877
+ pullQuote,
878
+ videoWithCaption,
879
+ videoPullQuote,
880
+ dataTable,
881
+ diagram,
882
+ tree,
883
+ timeline,
884
+ layout,
885
+ drawing
886
+ };
887
+
888
+ // src/doc/page/materializePageSection.ts
889
+ function resolvePageStyle(theme, hints) {
890
+ const base = theme?.pageStyle ?? defaultPageStyle(theme ?? DEFAULT_THEME);
891
+ if (!hints?.spacing || hints.spacing === base.tokens.sectionSpacing) return base;
892
+ return { ...base, tokens: { ...base.tokens, sectionSpacing: hints.spacing } };
893
+ }
894
+ var ACCENT_KINDS = /* @__PURE__ */ new Set([
895
+ "banner",
896
+ "stat-band",
897
+ "quote-band",
898
+ "callout",
899
+ "card-grid",
900
+ "item-list",
901
+ "timeline-rail",
902
+ "footer"
903
+ ]);
904
+ var BAND_KINDS = /* @__PURE__ */ new Set([
905
+ "banner",
906
+ "quote-band",
907
+ "stat-band",
908
+ "footer"
909
+ ]);
910
+ var PANEL_KINDS = /* @__PURE__ */ new Set([
911
+ "callout",
912
+ "card-grid",
913
+ "stat-band",
914
+ "item-list",
915
+ "timeline-rail",
916
+ "table-section"
917
+ ]);
918
+ function isMermaidFence(node) {
919
+ return node.type === "code" && node.lang?.trim().toLowerCase() === "mermaid";
920
+ }
921
+ function htmlTreeContainsMedia(nodes) {
922
+ for (const value of nodes) {
923
+ if (!value || typeof value !== "object") continue;
924
+ const node = value;
925
+ if (node.type === "htmlElement" && typeof node.tagName === "string" && ["img", "video", "audio"].includes(node.tagName.toLowerCase())) {
926
+ return true;
927
+ }
928
+ if (Array.isArray(node.children) && htmlTreeContainsMedia(node.children)) return true;
929
+ }
930
+ return false;
931
+ }
932
+ function markdownNodeContainsMedia(value) {
933
+ if (!value || typeof value !== "object") return false;
934
+ const node = value;
935
+ if (node.type === "image") return true;
936
+ if ((node.type === "htmlBlock" || node.type === "htmlInline") && Array.isArray(node.htmlChildren) && htmlTreeContainsMedia(node.htmlChildren)) {
937
+ return true;
938
+ }
939
+ return Array.isArray(node.children) && node.children.some(markdownNodeContainsMedia);
940
+ }
941
+ function unconsumedRichContent(block, draft) {
942
+ if (!block.contents || block.contents.length === 0) return void 0;
943
+ const templateHasMedia = Boolean(draft.slots.media) || Boolean(draft.slots.items?.some((item) => item.media !== void 0));
944
+ const markdown = block.contents.filter(
945
+ (node) => isMermaidFence(node) || !templateHasMedia && markdownNodeContainsMedia(node)
946
+ );
947
+ if (markdown.length === 0) return void 0;
948
+ return {
949
+ text: markdown.map((node) => extractPlainText(node)).join("\n").trim(),
950
+ markdown
951
+ };
952
+ }
953
+ function preserveRichContent(block, draft) {
954
+ const richContent = unconsumedRichContent(block, draft);
955
+ return richContent ? { ...draft, slots: { ...draft.slots, richContent } } : draft;
956
+ }
957
+ function draftForBlock(block, viewport, customTemplates) {
958
+ if (isTemplatedPageBlock(block)) {
959
+ const resolved = resolvePageBlock(block);
960
+ const templateName = resolved.templateName;
961
+ const extractor = sectionExtractors[templateName];
962
+ if (extractor) {
963
+ return {
964
+ draft: preserveRichContent(block, extractor(resolved.templateBlock, { block, viewport })),
965
+ source: "template",
966
+ templateName
967
+ };
968
+ }
969
+ const custom = customTemplates?.find((definition) => definition.name === templateName);
970
+ if (custom) {
971
+ const draft2 = {
972
+ kind: "canvas-embed",
973
+ variant: "custom",
974
+ slots: {
975
+ media: {
976
+ type: "canvas",
977
+ spatial: "custom",
978
+ block: resolved.templateBlock,
979
+ aspect: {
980
+ width: custom.viewport?.width ?? viewport.width,
981
+ height: custom.viewport?.height ?? viewport.height
982
+ }
983
+ }
984
+ }
985
+ };
986
+ return {
987
+ draft: preserveRichContent(block, draft2),
988
+ source: "custom-template",
989
+ templateName
990
+ };
991
+ }
992
+ const diagnostic = {
993
+ code: "unknown-template",
994
+ template: templateName,
995
+ message: `Unknown template "${templateName}"`
996
+ };
997
+ const headingText = block.sourceHeading ? extractPlainText(block.sourceHeading) : void 0;
998
+ const draft = {
999
+ kind: "callout",
1000
+ variant: "diagnostic",
1001
+ slots: {
1002
+ title: headingText ?? diagnostic.message,
1003
+ body: { text: extractBodyPlainText(block.contents) },
1004
+ meta: diagnostic.message
1005
+ },
1006
+ emphasis: "quiet"
1007
+ };
1008
+ return {
1009
+ draft: preserveRichContent(block, draft),
1010
+ source: "fallback",
1011
+ templateName,
1012
+ diagnostic
1013
+ };
1014
+ }
1015
+ if (block.layers && block.layers.length > 0) {
1016
+ const draft = {
1017
+ kind: "canvas-embed",
1018
+ variant: "authored",
1019
+ slots: {
1020
+ media: {
1021
+ type: "canvas",
1022
+ spatial: "authored",
1023
+ block,
1024
+ aspect: { width: viewport.width, height: viewport.height }
1025
+ }
1026
+ }
1027
+ };
1028
+ return {
1029
+ draft: preserveRichContent(block, draft),
1030
+ source: "authored"
1031
+ };
1032
+ }
1033
+ const heading = block.sourceHeading;
1034
+ return {
1035
+ draft: {
1036
+ kind: "prose",
1037
+ slots: {
1038
+ title: heading ? extractPlainText(heading) : void 0,
1039
+ headingLevel: heading?.depth,
1040
+ body: block.contents && block.contents.length > 0 ? { text: extractBodyPlainText(block.contents), markdown: block.contents } : void 0
1041
+ }
1042
+ },
1043
+ source: "prose"
1044
+ };
1045
+ }
1046
+ function overrideFor(pageStyle, kind, templateName) {
1047
+ const byTemplate = templateName ? pageStyle.templates?.[templateName] : void 0;
1048
+ const byKind = pageStyle.sections?.[kind];
1049
+ if (!byTemplate) return byKind;
1050
+ if (!byKind) return byTemplate;
1051
+ return {
1052
+ ...byKind,
1053
+ ...byTemplate,
1054
+ hints: { ...byKind.hints, ...byTemplate.hints }
1055
+ };
1056
+ }
1057
+ function buildSection(seed, index, totalSections, background, emphasis, accent) {
1058
+ const { draft, override } = seed;
1059
+ const hints = { ...draft.hints, ...override?.hints };
1060
+ const section = {
1061
+ kind: override?.kind ?? draft.kind,
1062
+ variant: override?.variant ?? draft.variant,
1063
+ blockId: seed.block?.id ?? "cover",
1064
+ template: seed.source === "template" || seed.source === "custom-template" || seed.source === "fallback" ? seed.templateName : void 0,
1065
+ slots: draft.slots,
1066
+ emphasis,
1067
+ accent,
1068
+ background,
1069
+ index,
1070
+ totalSections,
1071
+ depth: seed.depth,
1072
+ source: seed.source
1073
+ };
1074
+ if (seed.diagnostic) section.diagnostic = seed.diagnostic;
1075
+ if (Object.keys(hints).length > 0) section.hints = hints;
1076
+ return section;
1077
+ }
1078
+ function resolveScheme(theme, schemeName) {
1079
+ return schemeName ? theme.colorSchemes?.[schemeName] : void 0;
1080
+ }
1081
+ function rotationSchemeNames(pageStyle, theme) {
1082
+ const all = Object.keys(theme.colorSchemes ?? {});
1083
+ const requested = pageStyle.accentRotation.schemes;
1084
+ if (!requested || requested.length === 0) return all;
1085
+ return requested.filter((name) => all.includes(name));
1086
+ }
1087
+ function materializePageSection(block, options = {}) {
1088
+ const theme = options.theme ?? DEFAULT_THEME;
1089
+ const viewport = options.viewport ?? VIEWPORT_PRESETS.landscape;
1090
+ const pageStyle = resolvePageStyle(theme);
1091
+ const result = draftForBlock(block, viewport, options.customTemplates);
1092
+ const override = overrideFor(pageStyle, result.draft.kind, result.templateName);
1093
+ const background = override?.background ?? (result.draft.mediaBackground ? "media" : "base");
1094
+ const emphasis = override?.emphasis ?? result.draft.emphasis ?? "standard";
1095
+ const accent = result.draft.colorScheme ? {
1096
+ schemeName: result.draft.colorScheme,
1097
+ scheme: resolveScheme(theme, result.draft.colorScheme),
1098
+ role: "block"
1099
+ } : { role: pageStyle.accentRotation.strategy === "none" ? "none" : "primary" };
1100
+ const section = buildSection(
1101
+ { ...result, override, block, depth: 0 },
1102
+ options.blockIndex ?? 0,
1103
+ options.totalBlocks ?? 1,
1104
+ background,
1105
+ emphasis,
1106
+ accent
1107
+ );
1108
+ return {
1109
+ section,
1110
+ block,
1111
+ source: result.source,
1112
+ diagnostic: result.diagnostic
1113
+ };
1114
+ }
1115
+ function materializePageSections(doc, options = {}) {
1116
+ const theme = options.theme ?? DEFAULT_THEME;
1117
+ const viewport = options.viewport ?? VIEWPORT_PRESETS.landscape;
1118
+ const pageStyle = resolvePageStyle(theme, options.transformPage);
1119
+ const customTemplates = options.customTemplates ?? doc.customTemplates;
1120
+ const seeds = [];
1121
+ if (options.cover) {
1122
+ const cover = options.cover;
1123
+ seeds.push({
1124
+ draft: {
1125
+ kind: "hero",
1126
+ variant: "cover",
1127
+ slots: {
1128
+ title: cover.title,
1129
+ subtitle: cover.subtitle,
1130
+ media: cover.heroSrc ? {
1131
+ type: "image",
1132
+ src: cover.heroSrc,
1133
+ alt: cover.heroAlt ?? "",
1134
+ credit: cover.heroCredit,
1135
+ license: cover.heroLicense
1136
+ } : void 0
1137
+ },
1138
+ emphasis: "lead",
1139
+ mediaBackground: !!cover.heroSrc
1140
+ },
1141
+ source: "cover",
1142
+ depth: 0
1143
+ });
1144
+ }
1145
+ const walk = (blocks, depth) => {
1146
+ for (const block of blocks) {
1147
+ const result = draftForBlock(block, viewport, customTemplates);
1148
+ seeds.push({ ...result, block, depth });
1149
+ const consumed = result.draft.kind === "canvas-embed" && isContainerTemplate(result.templateName);
1150
+ if (!consumed && block.children && block.children.length > 0) {
1151
+ walk(block.children, depth + 1);
1152
+ }
1153
+ }
1154
+ };
1155
+ walk(doc.blocks ?? [], 0);
1156
+ if (options.cover && seeds.length > 1) {
1157
+ const cover = options.cover;
1158
+ const first = seeds[1];
1159
+ if (first.draft.kind === "hero" && first.draft.slots.title === cover.title) {
1160
+ const coverSeed = seeds[0];
1161
+ const coverMedia = coverSeed.draft.slots.media;
1162
+ if (coverMedia && !first.draft.slots.media) {
1163
+ first.draft = {
1164
+ ...first.draft,
1165
+ slots: { ...first.draft.slots, media: coverMedia },
1166
+ mediaBackground: true
1167
+ };
1168
+ }
1169
+ seeds.splice(0, 1);
1170
+ } else if (first.draft.kind === "prose" && first.draft.slots.title === cover.title) {
1171
+ const slots = { ...first.draft.slots };
1172
+ delete slots.title;
1173
+ delete slots.headingLevel;
1174
+ let markdown = slots.body?.markdown;
1175
+ if (cover.subtitle && markdown && markdown.length > 0 && markdown[0].type === "paragraph" && extractPlainText(markdown[0]) === cover.subtitle) {
1176
+ markdown = markdown.slice(1);
1177
+ }
1178
+ if (markdown && markdown.length > 0) {
1179
+ slots.body = {
1180
+ text: markdown.map((node) => extractPlainText(node)).join("\n").trim(),
1181
+ markdown
1182
+ };
1183
+ first.draft = { ...first.draft, slots };
1184
+ } else {
1185
+ seeds.splice(1, 1);
1186
+ }
1187
+ }
1188
+ }
1189
+ for (const seed of seeds) {
1190
+ seed.override = overrideFor(pageStyle, seed.draft.kind, seed.templateName);
1191
+ }
1192
+ const totalSections = seeds.length;
1193
+ const rhythm = pageStyle.tokens.backgroundRhythm;
1194
+ const strategy = pageStyle.accentRotation.strategy;
1195
+ const schemeNames = rotationSchemeNames(pageStyle, theme);
1196
+ const rotationSize = strategy === "alternate-two" ? Math.min(2, schemeNames.length) : schemeNames.length;
1197
+ let bandCounter = 0;
1198
+ let rotationCounter = 0;
1199
+ let promotedCount = 0;
1200
+ let eyebrowCounter = 0;
1201
+ const eyebrowTreatment = pageStyle.tokens.headingTreatment.eyebrow;
1202
+ const results = [];
1203
+ for (let index = 0; index < seeds.length; index++) {
1204
+ const seed = seeds[index];
1205
+ const kind = seed.override?.kind ?? seed.draft.kind;
1206
+ let background;
1207
+ if (seed.override?.background) {
1208
+ background = seed.override.background;
1209
+ } else if (seed.draft.mediaBackground) {
1210
+ background = "media";
1211
+ } else if (kind === "prose" || rhythm === "flat") {
1212
+ background = "base";
1213
+ } else if (rhythm === "accent-bands" && BAND_KINDS.has(kind)) {
1214
+ background = "accent";
1215
+ } else if (rhythm === "tinted-panels") {
1216
+ background = PANEL_KINDS.has(kind) ? "alternate" : "base";
1217
+ } else if (rhythm === "alternate" || rhythm === "accent-bands") {
1218
+ background = bandCounter % 2 === 1 ? "alternate" : "base";
1219
+ bandCounter++;
1220
+ } else {
1221
+ background = "base";
1222
+ }
1223
+ let accent;
1224
+ if (seed.draft.colorScheme) {
1225
+ accent = {
1226
+ schemeName: seed.draft.colorScheme,
1227
+ scheme: resolveScheme(theme, seed.draft.colorScheme),
1228
+ role: "block"
1229
+ };
1230
+ } else if (ACCENT_KINDS.has(kind) && (strategy === "cycle" || strategy === "alternate-two") && rotationSize > 0) {
1231
+ const schemeName = schemeNames[rotationCounter % rotationSize];
1232
+ rotationCounter++;
1233
+ accent = { schemeName, scheme: resolveScheme(theme, schemeName), role: "rotation" };
1234
+ } else if (strategy === "none") {
1235
+ accent = { role: "none" };
1236
+ } else {
1237
+ accent = { role: "primary" };
1238
+ }
1239
+ let emphasis = seed.override?.emphasis ?? seed.draft.emphasis ?? "standard";
1240
+ if (options.transformPage?.emphasisCurve === "front-loaded" && kind !== "hero" && kind !== "prose" && promotedCount < 2) {
1241
+ if (emphasis === "standard") emphasis = "strong";
1242
+ promotedCount++;
1243
+ }
1244
+ if ((eyebrowTreatment === "numbered" || eyebrowTreatment === "mono-tag") && (kind === "hero" || kind === "banner")) {
1245
+ eyebrowCounter++;
1246
+ if (!seed.draft.slots.eyebrow) {
1247
+ seed.draft.slots = {
1248
+ ...seed.draft.slots,
1249
+ eyebrow: String(eyebrowCounter).padStart(2, "0")
1250
+ };
1251
+ }
1252
+ }
1253
+ const section = buildSection(seed, index, totalSections, background, emphasis, accent);
1254
+ results.push({
1255
+ section,
1256
+ block: seed.block,
1257
+ source: seed.source,
1258
+ diagnostic: seed.diagnostic
1259
+ });
1260
+ }
1261
+ return results;
1262
+ }
1263
+
1264
+ // src/doc/pageCss.ts
1265
+ var NOISE_DATA_URI = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='0.35'/%3E%3C/svg%3E")`;
1266
+ function buildPageCssVars(theme, pageStyle) {
1267
+ const t = theme ?? DEFAULT_THEME;
1268
+ const style = pageStyle ?? resolvePageStyle(t);
1269
+ const colors = t.colors;
1270
+ const typography = t.typography;
1271
+ return {
1272
+ "--squisq-page-bg": colors.background,
1273
+ "--squisq-page-bg-alt": colors.backgroundLight,
1274
+ "--squisq-page-text": colors.text,
1275
+ "--squisq-page-text-muted": colors.textMuted,
1276
+ "--squisq-page-primary": colors.primary,
1277
+ "--squisq-page-secondary": colors.secondary,
1278
+ "--squisq-page-highlight": colors.highlight,
1279
+ "--squisq-page-title-font": resolveFontFamily(typography.titleFont, "Georgia, serif"),
1280
+ "--squisq-page-body-font": resolveFontFamily(typography.bodyFont, "system-ui, sans-serif"),
1281
+ "--squisq-page-mono-font": resolveFontFamily(
1282
+ typography.monoFont,
1283
+ "ui-monospace, SFMono-Regular, Menlo, monospace"
1284
+ ),
1285
+ "--squisq-page-line-height": String(typography.lineHeight ?? 1.65),
1286
+ "--squisq-page-title-weight": typography.titleWeight === "normal" ? "400" : "700",
1287
+ "--squisq-page-content-max": `${style.tokens.contentMaxWidth}px`,
1288
+ "--squisq-page-wide-max": `${style.tokens.wideMaxWidth}px`,
1289
+ "--squisq-page-radius": `${style.tokens.cornerRadius}px`,
1290
+ // Per-section accent defaults; the renderer overrides these per section.
1291
+ "--squisq-page-accent": colors.primary,
1292
+ "--squisq-page-accent-bg": colors.backgroundLight,
1293
+ "--squisq-page-accent-text": colors.text
1294
+ };
1295
+ }
1296
+ function pageStyleDataAttributes(pageStyle) {
1297
+ const tokens = pageStyle.tokens;
1298
+ const attrs = {
1299
+ "data-family": pageStyle.family,
1300
+ "data-spacing": tokens.sectionSpacing,
1301
+ "data-divider": tokens.divider,
1302
+ "data-rhythm": tokens.backgroundRhythm,
1303
+ "data-hero-style": tokens.heroStyle,
1304
+ "data-eyebrow": tokens.headingTreatment.eyebrow,
1305
+ "data-heading-scale": tokens.headingTreatment.scale,
1306
+ "data-framing": tokens.imageFraming,
1307
+ "data-shadow": tokens.shadow,
1308
+ "data-quote-mark": tokens.quoteMark,
1309
+ "data-numerals": tokens.numeralStyle
1310
+ };
1311
+ if (tokens.headingTreatment.case && tokens.headingTreatment.case !== "none") {
1312
+ attrs["data-heading-case"] = tokens.headingTreatment.case;
1313
+ }
1314
+ if (tokens.headingTreatment.underline && tokens.headingTreatment.underline !== "none") {
1315
+ attrs["data-underline"] = tokens.headingTreatment.underline;
1316
+ }
1317
+ if (tokens.pattern && tokens.pattern !== "none") {
1318
+ attrs["data-pattern"] = tokens.pattern;
1319
+ }
1320
+ return attrs;
1321
+ }
1322
+ var NARROW_RULES = `
1323
+ .squisq-page-hero-grid { grid-template-columns: 1fr; gap: 1.5rem; }
1324
+ .squisq-page-feature { grid-template-columns: 1fr; }
1325
+ .squisq-page-feature--media-right .squisq-page-feature-media { order: 0; }
1326
+ .squisq-page-stats { flex-direction: column; gap: 1.75rem; }
1327
+ .squisq-page-cards { grid-template-columns: 1fr; }
1328
+ .squisq-page-gallery { grid-template-columns: repeat(2, 1fr); }
1329
+ .squisq-page-milestone { grid-template-columns: 1fr; gap: 0.5rem; }
1330
+ .squisq-page-milestone-rail { display: none; }
1331
+ .squisq-page-section-inner { padding-inline: 18px; }
1332
+ `;
1333
+ var PAGE_BASE_CSS = `
1334
+ /* \u2500\u2500 Base \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1335
+ .squisq-page {
1336
+ background: var(--squisq-page-bg);
1337
+ color: var(--squisq-page-text);
1338
+ font-family: var(--squisq-page-body-font);
1339
+ line-height: var(--squisq-page-line-height);
1340
+ --squisq-page-divider-color: color-mix(in srgb, var(--squisq-page-text) 16%, transparent);
1341
+ --squisq-page-section-pad: 3.5rem;
1342
+ --squisq-page-shadow: none;
1343
+ }
1344
+ .squisq-page *, .squisq-page *::before, .squisq-page *::after { box-sizing: border-box; }
1345
+ .squisq-page img { max-width: 100%; height: auto; }
1346
+
1347
+ /* Page pattern washes (very low intensity) */
1348
+ .squisq-page[data-pattern='dots'] {
1349
+ background-image: radial-gradient(color-mix(in srgb, var(--squisq-page-text) 7%, transparent) 1px, transparent 1px);
1350
+ background-size: 22px 22px;
1351
+ }
1352
+ .squisq-page[data-pattern='grid'] {
1353
+ background-image:
1354
+ linear-gradient(color-mix(in srgb, var(--squisq-page-primary) 7%, transparent) 1px, transparent 1px),
1355
+ linear-gradient(90deg, color-mix(in srgb, var(--squisq-page-primary) 7%, transparent) 1px, transparent 1px);
1356
+ background-size: 44px 44px;
1357
+ }
1358
+ .squisq-page[data-pattern='diagonal'] {
1359
+ background-image: repeating-linear-gradient(
1360
+ -45deg,
1361
+ color-mix(in srgb, var(--squisq-page-text) 4%, transparent) 0 1px,
1362
+ transparent 1px 14px
1363
+ );
1364
+ }
1365
+ .squisq-page[data-pattern='noise'] { background-image: ${NOISE_DATA_URI}; }
1366
+
1367
+ /* Spacing scale */
1368
+ .squisq-page[data-spacing='compact'] { --squisq-page-section-pad: 2.25rem; }
1369
+ .squisq-page[data-spacing='comfortable'] { --squisq-page-section-pad: 3.5rem; }
1370
+ .squisq-page[data-spacing='generous'] { --squisq-page-section-pad: 5.25rem; }
1371
+
1372
+ /* Shadow language */
1373
+ .squisq-page[data-shadow='soft'] { --squisq-page-shadow: 0 14px 36px color-mix(in srgb, var(--squisq-page-text) 14%, transparent); }
1374
+ .squisq-page[data-shadow='crisp'] { --squisq-page-shadow: 0 2px 10px color-mix(in srgb, var(--squisq-page-text) 26%, transparent); }
1375
+ .squisq-page[data-shadow='heavy'] { --squisq-page-shadow: 10px 10px 0 color-mix(in srgb, var(--squisq-page-text) 82%, transparent); }
1376
+
1377
+ /* \u2500\u2500 Sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1378
+ .squisq-page-section { position: relative; padding-block: var(--squisq-page-section-pad); }
1379
+ .squisq-page-section-inner {
1380
+ max-width: var(--squisq-page-content-max);
1381
+ margin-inline: auto;
1382
+ padding-inline: 24px;
1383
+ }
1384
+ /* Backdrops anchor to the section; these content roots stack above them. */
1385
+ .squisq-page-hero-body,
1386
+ .squisq-page-banner-body,
1387
+ .squisq-page-quote-figure { position: relative; }
1388
+ .squisq-page-section--feature-split .squisq-page-section-inner,
1389
+ .squisq-page-section--gallery .squisq-page-section-inner,
1390
+ .squisq-page-section--table-section .squisq-page-section-inner,
1391
+ .squisq-page-section--canvas-embed .squisq-page-section-inner,
1392
+ .squisq-page-section--stat-band .squisq-page-section-inner,
1393
+ .squisq-page-section--card-grid .squisq-page-section-inner,
1394
+ .squisq-page-section--media-figure .squisq-page-section-inner,
1395
+ .squisq-page-section--hero .squisq-page-section-inner {
1396
+ max-width: var(--squisq-page-wide-max);
1397
+ }
1398
+
1399
+ /* Background rhythm */
1400
+ .squisq-page-section--bg-alternate { background: var(--squisq-page-bg-alt); }
1401
+ .squisq-page-section--bg-accent {
1402
+ background: var(--squisq-page-accent-bg);
1403
+ color: var(--squisq-page-accent-text);
1404
+ }
1405
+ .squisq-page-section--bg-media { color: #ffffff; }
1406
+
1407
+ /* Dividers between adjacent sections */
1408
+ .squisq-page[data-divider='hairline'] .squisq-page-section + .squisq-page-section { border-top: 1px solid var(--squisq-page-divider-color); }
1409
+ .squisq-page[data-divider='thick-rule'] .squisq-page-section + .squisq-page-section { border-top: 3px solid var(--squisq-page-primary); }
1410
+ .squisq-page[data-divider='double-rule'] .squisq-page-section + .squisq-page-section { border-top: 4px double var(--squisq-page-divider-color); }
1411
+ .squisq-page[data-divider='dotted'] .squisq-page-section + .squisq-page-section { border-top: 2px dotted var(--squisq-page-divider-color); }
1412
+ /* Banded sections carry their own edges; media sections never need rules. */
1413
+ .squisq-page .squisq-page-section--bg-media,
1414
+ .squisq-page .squisq-page-section--bg-media + .squisq-page-section,
1415
+ .squisq-page .squisq-page-section--timeline-rail + .squisq-page-section--timeline-rail { border-top: none; }
1416
+
1417
+ /* \u2500\u2500 Headings, eyebrows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1418
+ .squisq-page-section-title {
1419
+ font-family: var(--squisq-page-title-font);
1420
+ font-weight: var(--squisq-page-title-weight);
1421
+ line-height: 1.15;
1422
+ margin: 0 0 0.5em;
1423
+ }
1424
+ .squisq-page[data-heading-case='uppercase'] .squisq-page-section-title { text-transform: uppercase; letter-spacing: 0.03em; }
1425
+ .squisq-page[data-underline='accent-bar'] .squisq-page-section-title::after {
1426
+ content: '';
1427
+ display: block;
1428
+ width: 56px;
1429
+ height: 4px;
1430
+ margin-top: 0.4em;
1431
+ border-radius: 2px;
1432
+ background: var(--squisq-page-accent);
1433
+ }
1434
+ .squisq-page[data-underline='full-rule'] .squisq-page-section-title {
1435
+ border-bottom: 1px solid var(--squisq-page-divider-color);
1436
+ padding-bottom: 0.35em;
1437
+ }
1438
+
1439
+ .squisq-page-eyebrow {
1440
+ display: block;
1441
+ font-size: 0.8125rem;
1442
+ font-weight: 600;
1443
+ letter-spacing: 0.14em;
1444
+ text-transform: uppercase;
1445
+ color: var(--squisq-page-accent);
1446
+ margin: 0 0 0.9em;
1447
+ }
1448
+ .squisq-page[data-eyebrow='numbered'] .squisq-page-eyebrow::after { content: ' \u2014'; color: var(--squisq-page-text-muted); }
1449
+ .squisq-page[data-eyebrow='mono-tag'] .squisq-page-eyebrow {
1450
+ display: inline-block;
1451
+ font-family: var(--squisq-page-mono-font);
1452
+ text-transform: none;
1453
+ letter-spacing: 0.06em;
1454
+ border: 1px solid color-mix(in srgb, var(--squisq-page-accent) 55%, transparent);
1455
+ border-radius: var(--squisq-page-radius);
1456
+ padding: 0.15em 0.6em;
1457
+ background: color-mix(in srgb, var(--squisq-page-accent) 10%, transparent);
1458
+ }
1459
+ .squisq-page[data-eyebrow='mono-tag'] .squisq-page-eyebrow::before { content: '['; opacity: 0.6; }
1460
+ .squisq-page[data-eyebrow='mono-tag'] .squisq-page-eyebrow::after { content: ']'; opacity: 0.6; }
1461
+
1462
+ /* \u2500\u2500 Hero \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1463
+ .squisq-page-section--hero { padding-block: calc(var(--squisq-page-section-pad) * 1.5); }
1464
+ .squisq-page-hero-title {
1465
+ font-family: var(--squisq-page-title-font);
1466
+ font-weight: var(--squisq-page-title-weight);
1467
+ line-height: 1.08;
1468
+ margin: 0;
1469
+ font-size: 2.75rem;
1470
+ }
1471
+ .squisq-page[data-heading-scale='display'] .squisq-page-hero-title { font-size: 3.4rem; }
1472
+ .squisq-page[data-heading-scale='oversized'] .squisq-page-hero-title { font-size: 4rem; font-size: clamp(3rem, 9cqw, 6rem); line-height: 1.02; }
1473
+ .squisq-page[data-heading-case='uppercase'] .squisq-page-hero-title { text-transform: uppercase; letter-spacing: 0.02em; }
1474
+ .squisq-page-hero-subtitle {
1475
+ margin: 1.1em 0 0;
1476
+ font-size: 1.25rem;
1477
+ color: var(--squisq-page-text-muted);
1478
+ max-width: 42em;
1479
+ white-space: pre-line;
1480
+ }
1481
+ .squisq-page-section--bg-media .squisq-page-hero-subtitle { color: rgba(255, 255, 255, 0.88); }
1482
+
1483
+ /* Stacked (default): centered column */
1484
+ .squisq-page[data-hero-style='stacked'] .squisq-page-hero-body { text-align: center; }
1485
+ .squisq-page[data-hero-style='stacked'] .squisq-page-hero-subtitle { margin-inline: auto; }
1486
+
1487
+ /* Oversized type: hard left, no decoration */
1488
+ .squisq-page[data-hero-style='oversized-type'] .squisq-page-hero-title { font-size: 4.25rem; font-size: clamp(3.25rem, 10cqw, 6.5rem); line-height: 0.98; }
1489
+
1490
+ /* Split: text and media side by side */
1491
+ .squisq-page-hero-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center; }
1492
+ .squisq-page-hero-grid .squisq-page-hero-media img { width: 100%; object-fit: cover; }
1493
+
1494
+ /* Full-bleed & letterbox: media behind text */
1495
+ .squisq-page-section--hero-media {
1496
+ padding-block: 0;
1497
+ min-height: min(72svh, 620px);
1498
+ display: flex;
1499
+ align-items: flex-end;
1500
+ }
1501
+ .squisq-page[data-hero-style='letterbox'] .squisq-page-section--hero-media { min-height: min(52svh, 460px); }
1502
+ .squisq-page-hero-backdrop { position: absolute; inset: 0; overflow: hidden; }
1503
+ .squisq-page-hero-backdrop img { width: 100%; height: 100%; object-fit: cover; }
1504
+ .squisq-page-hero-backdrop::after {
1505
+ content: '';
1506
+ position: absolute;
1507
+ inset: 0;
1508
+ background: linear-gradient(180deg, rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.68) 100%);
1509
+ }
1510
+ .squisq-page[data-hero-style='letterbox'] .squisq-page-hero-backdrop img { filter: saturate(0.9); }
1511
+ .squisq-page-section--hero-media .squisq-page-section-inner { padding-block: 3rem; width: 100%; }
1512
+
1513
+ /* \u2500\u2500 Banner (sectionHeader) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1514
+ .squisq-page-banner-title { font-size: 2rem; }
1515
+ .squisq-page[data-heading-scale='display'] .squisq-page-banner-title { font-size: 2.5rem; }
1516
+ .squisq-page[data-heading-scale='oversized'] .squisq-page-banner-title { font-size: 3rem; font-size: clamp(2.25rem, 6cqw, 3.75rem); }
1517
+ .squisq-page-section--banner.squisq-page-section--bg-media { padding-block: 0; min-height: 280px; display: flex; align-items: flex-end; }
1518
+ .squisq-page-section--banner.squisq-page-section--bg-media .squisq-page-section-inner { padding-block: 2rem; width: 100%; }
1519
+ .squisq-page-section--banner .squisq-page-section-title { margin-bottom: 0; }
1520
+
1521
+ /* \u2500\u2500 Stat band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1522
+ .squisq-page-stats { display: flex; gap: 3rem; justify-content: center; text-align: center; flex-wrap: wrap; }
1523
+ .squisq-page-stat { flex: 1 1 220px; max-width: 420px; }
1524
+ .squisq-page-stat-value {
1525
+ display: block;
1526
+ font-family: var(--squisq-page-title-font);
1527
+ font-weight: 700;
1528
+ font-size: 3.25rem;
1529
+ line-height: 1;
1530
+ color: var(--squisq-page-accent);
1531
+ }
1532
+ .squisq-page[data-numerals='oversized'] .squisq-page-stat-value { font-size: 4.5rem; font-size: clamp(3.5rem, 8cqw, 5.5rem); }
1533
+ .squisq-page[data-numerals='mono'] .squisq-page-stat-value { font-family: var(--squisq-page-mono-font); letter-spacing: -0.02em; }
1534
+ .squisq-page[data-numerals='boxed'] .squisq-page-stat-value {
1535
+ display: inline-block;
1536
+ border: 2px solid var(--squisq-page-accent);
1537
+ border-radius: var(--squisq-page-radius);
1538
+ padding: 0.18em 0.4em;
1539
+ }
1540
+ .squisq-page-stat-title { display: block; margin-top: 0.9em; font-size: 1.125rem; font-weight: 600; }
1541
+ .squisq-page-stat-body { display: block; margin-top: 0.45em; color: var(--squisq-page-text-muted); font-size: 0.95rem; }
1542
+ .squisq-page-stat-meta { text-align: center; margin-top: 1.5rem; color: var(--squisq-page-text-muted); font-size: 0.85rem; }
1543
+ .squisq-page-stat-bar { height: 10px; border-radius: 999px; background: var(--squisq-page-accent); margin-top: 0.8em; }
1544
+ .squisq-page-stat--bars { text-align: left; }
1545
+
1546
+ /* \u2500\u2500 Quote band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1547
+ .squisq-page-quote {
1548
+ margin: 0;
1549
+ font-family: var(--squisq-page-title-font);
1550
+ font-size: 1.6rem;
1551
+ line-height: 1.35;
1552
+ white-space: pre-line;
1553
+ }
1554
+ .squisq-page-section--em-strong .squisq-page-quote { font-size: 2.1rem; }
1555
+ .squisq-page-section--em-quiet .squisq-page-quote { font-size: 1.25rem; color: var(--squisq-page-text-muted); }
1556
+ .squisq-page-quote-attribution { margin-top: 1.1em; font-family: var(--squisq-page-body-font); font-size: 0.95rem; color: var(--squisq-page-text-muted); }
1557
+ .squisq-page-quote-attribution::before { content: '\u2014 '; }
1558
+ .squisq-page[data-quote-mark='accent-bar'] .squisq-page-quote-figure { border-left: 4px solid var(--squisq-page-accent); padding-left: 1.5rem; }
1559
+ .squisq-page[data-quote-mark='oversized-glyph'] .squisq-page-quote-figure { position: relative; padding-top: 1.25rem; }
1560
+ .squisq-page[data-quote-mark='oversized-glyph'] .squisq-page-quote-figure::before {
1561
+ content: '\\201C';
1562
+ position: absolute;
1563
+ top: -0.12em;
1564
+ left: -0.05em;
1565
+ font-family: var(--squisq-page-title-font);
1566
+ font-size: 5.5rem;
1567
+ line-height: 1;
1568
+ color: color-mix(in srgb, var(--squisq-page-accent) 42%, transparent);
1569
+ pointer-events: none;
1570
+ }
1571
+ .squisq-page-section--v-display .squisq-page-quote-figure { text-align: center; border-left: none; }
1572
+ .squisq-page-section--v-display .squisq-page-quote { font-size: 2.4rem; font-size: clamp(1.9rem, 5cqw, 3rem); }
1573
+ .squisq-page-section--v-editorial .squisq-page-quote-figure {
1574
+ border-block: 3px solid var(--squisq-page-primary);
1575
+ border-left: none;
1576
+ padding: 2rem 0.5rem;
1577
+ }
1578
+ /* Full-bleed quote over media */
1579
+ .squisq-page-section--quote-band.squisq-page-section--bg-media { padding-block: 0; min-height: 380px; display: flex; align-items: center; }
1580
+ .squisq-page-section--quote-band.squisq-page-section--bg-media .squisq-page-section-inner { padding-block: 3.5rem; }
1581
+ .squisq-page-quote-backdrop { position: absolute; inset: 0; overflow: hidden; }
1582
+ .squisq-page-quote-backdrop img, .squisq-page-quote-backdrop video { width: 100%; height: 100%; object-fit: cover; }
1583
+ .squisq-page-quote-backdrop::after { content: ''; position: absolute; inset: 0; background: rgba(0, 0, 0, 0.55); }
1584
+ .squisq-page-section--quote-band[data-hint-vignette] .squisq-page-quote-backdrop::after {
1585
+ background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0.75) 100%);
1586
+ }
1587
+ .squisq-page-section--quote-band.squisq-page-section--bg-media .squisq-page-quote-figure { border: none; text-align: center; }
1588
+
1589
+ /* \u2500\u2500 Feature split \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1590
+ .squisq-page-feature { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center; }
1591
+ .squisq-page-feature--media-right .squisq-page-feature-media { order: 2; }
1592
+ .squisq-page-feature-media img { width: 100%; object-fit: cover; }
1593
+ .squisq-page-feature-title { font-size: 1.75rem; }
1594
+ .squisq-page-feature-body { color: var(--squisq-page-text-muted); font-size: 1.05rem; white-space: pre-line; margin: 0; }
1595
+
1596
+ /* \u2500\u2500 Media figure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1597
+ .squisq-page-figure { margin: 0; }
1598
+ .squisq-page-figure img, .squisq-page-figure video { width: 100%; display: block; }
1599
+ .squisq-page-figure figcaption { margin-top: 0.9em; font-size: 0.9rem; color: var(--squisq-page-text-muted); text-align: center; }
1600
+ .squisq-page-media-credit { font-size: 0.78rem; opacity: 0.75; }
1601
+
1602
+ /* Media frame treatment (figures, features, gallery tiles, cards) */
1603
+ .squisq-page-media-frame { overflow: hidden; }
1604
+ .squisq-page[data-framing='rounded'] .squisq-page-media-frame { border-radius: var(--squisq-page-radius); }
1605
+ .squisq-page[data-framing='bordered'] .squisq-page-media-frame { border: 3px solid var(--squisq-page-text); }
1606
+ .squisq-page[data-framing='polaroid'] .squisq-page-media-frame {
1607
+ background: #ffffff;
1608
+ padding: 10px 10px 16px;
1609
+ border: 1px solid rgba(0, 0, 0, 0.12);
1610
+ border-radius: 2px;
1611
+ }
1612
+ .squisq-page[data-framing='letterboxed'] .squisq-page-media-frame img { aspect-ratio: 21 / 9; object-fit: cover; }
1613
+ .squisq-page[data-framing='circle-accent'] .squisq-page-media-frame { border-radius: calc(var(--squisq-page-radius) * 2); }
1614
+ .squisq-page .squisq-page-media-frame { box-shadow: var(--squisq-page-shadow); }
1615
+
1616
+ /* Rich body nodes that the selected template did not consume. This universal
1617
+ * supplement keeps diagrams/media visible without making every template
1618
+ * duplicate the same preservation logic. */
1619
+ .squisq-page-rich-content {
1620
+ margin-top: clamp(1.5rem, 4vw, 3rem);
1621
+ padding-top: clamp(1.25rem, 3vw, 2rem);
1622
+ border-top: 1px solid var(--squisq-page-divider-color);
1623
+ }
1624
+ .squisq-page-rich-content :is(img, video) { display: block; max-width: 100%; height: auto; margin-inline: auto; }
1625
+ .squisq-page-rich-content .squisq-md-mermaid { min-height: min(520px, 62vh); margin-block: 0; }
1626
+
1627
+ /* \u2500\u2500 Gallery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1628
+ .squisq-page-gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.25rem; }
1629
+ .squisq-page-gallery .squisq-page-media-frame img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
1630
+ .squisq-page-gallery-caption { margin-top: 1.1rem; text-align: center; font-size: 0.9rem; color: var(--squisq-page-text-muted); }
1631
+
1632
+ /* \u2500\u2500 Callout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1633
+ .squisq-page-callout {
1634
+ border-radius: var(--squisq-page-radius);
1635
+ border: 1px solid color-mix(in srgb, var(--squisq-page-accent) 32%, transparent);
1636
+ border-left: 5px solid var(--squisq-page-accent);
1637
+ background: color-mix(in srgb, var(--squisq-page-accent) 7%, var(--squisq-page-bg));
1638
+ padding: 1.75rem 2rem;
1639
+ box-shadow: var(--squisq-page-shadow);
1640
+ display: flex;
1641
+ gap: 1.75rem;
1642
+ align-items: flex-start;
1643
+ }
1644
+ .squisq-page-callout-title { font-family: var(--squisq-page-title-font); font-size: 1.35rem; font-weight: 700; margin: 0 0 0.5em; }
1645
+ .squisq-page-callout-body { margin: 0; white-space: pre-line; }
1646
+ .squisq-page-callout-meta { margin-top: 0.9em; font-size: 0.82rem; color: var(--squisq-page-text-muted); }
1647
+ .squisq-page-callout .squisq-page-media-frame { flex: 0 0 132px; }
1648
+ .squisq-page-callout .squisq-page-media-frame img { width: 132px; height: 132px; object-fit: cover; }
1649
+ .squisq-page-callout[data-hint-framing='circle-accent'] .squisq-page-media-frame,
1650
+ .squisq-page-callout[data-hint-framing='circle-accent'] .squisq-page-media-frame img { border-radius: 50%; }
1651
+ .squisq-page-section--v-definition .squisq-page-callout-title { font-style: italic; }
1652
+ .squisq-page-section--v-diagnostic .squisq-page-callout { border-left-color: var(--squisq-page-highlight); }
1653
+
1654
+ /* \u2500\u2500 Card grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1655
+ .squisq-page-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1.5rem; }
1656
+ .squisq-page-card {
1657
+ border-radius: var(--squisq-page-radius);
1658
+ background: var(--squisq-page-bg-alt);
1659
+ border-top: 4px solid var(--squisq-page-card-accent, var(--squisq-page-accent));
1660
+ padding: 1.75rem 1.75rem 1.9rem;
1661
+ box-shadow: var(--squisq-page-shadow);
1662
+ }
1663
+ .squisq-page-card-title { font-family: var(--squisq-page-title-font); font-size: 1.3rem; margin: 0 0 0.4em; }
1664
+ .squisq-page-card-body { margin: 0; color: var(--squisq-page-text-muted); white-space: pre-line; }
1665
+ .squisq-page-cards-title { text-align: center; font-size: 1.9rem; margin-bottom: 1.75rem; }
1666
+
1667
+ /* \u2500\u2500 Item list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1668
+ .squisq-page-items { list-style: none; margin: 0; padding: 0; counter-reset: squisq-item; max-width: 40em; }
1669
+ .squisq-page-items li {
1670
+ counter-increment: squisq-item;
1671
+ position: relative;
1672
+ padding: 0.9em 0 0.9em 3.4em;
1673
+ font-size: 1.1rem;
1674
+ }
1675
+ .squisq-page-items li + li { border-top: 1px solid var(--squisq-page-divider-color); }
1676
+ .squisq-page-items li::before {
1677
+ content: counter(squisq-item, decimal-leading-zero);
1678
+ position: absolute;
1679
+ left: 0;
1680
+ top: 0.85em;
1681
+ font-family: var(--squisq-page-title-font);
1682
+ font-weight: 700;
1683
+ color: var(--squisq-page-accent);
1684
+ font-size: 1.15em;
1685
+ }
1686
+ .squisq-page[data-numerals='mono'] .squisq-page-items li::before { font-family: var(--squisq-page-mono-font); }
1687
+ .squisq-page-items-title { font-size: 1.9rem; }
1688
+
1689
+ /* \u2500\u2500 Timeline rail (dateEvent) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1690
+ .squisq-page-section--timeline-rail { padding-block: 1.4rem; }
1691
+ .squisq-page-section--timeline-rail:first-child { padding-top: var(--squisq-page-section-pad); }
1692
+ .squisq-page-milestone { display: grid; grid-template-columns: 150px 1fr; gap: 2rem; align-items: baseline; position: relative; }
1693
+ .squisq-page-milestone-date {
1694
+ font-family: var(--squisq-page-title-font);
1695
+ font-weight: 700;
1696
+ color: var(--squisq-page-accent);
1697
+ font-size: 1.05rem;
1698
+ text-align: right;
1699
+ }
1700
+ .squisq-page-milestone-rail {
1701
+ position: absolute;
1702
+ left: 166px;
1703
+ top: -1.4rem;
1704
+ bottom: -1.4rem;
1705
+ width: 2px;
1706
+ background: color-mix(in srgb, var(--squisq-page-accent) 35%, transparent);
1707
+ }
1708
+ .squisq-page-milestone-rail::after {
1709
+ content: '';
1710
+ position: absolute;
1711
+ left: 50%;
1712
+ top: 0.55em;
1713
+ width: 12px;
1714
+ height: 12px;
1715
+ border-radius: 50%;
1716
+ transform: translateX(-50%);
1717
+ background: var(--squisq-page-accent);
1718
+ border: 2px solid var(--squisq-page-bg);
1719
+ }
1720
+ .squisq-page-milestone-body { padding-left: 2.25rem; white-space: pre-line; }
1721
+ .squisq-page-milestone-footer { margin-top: 0.5em; font-size: 0.85rem; color: var(--squisq-page-text-muted); }
1722
+
1723
+ /* \u2500\u2500 Table section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1724
+ .squisq-page-table-title { font-size: 1.9rem; }
1725
+ .squisq-page-table-scroll { overflow-x: auto; border-radius: var(--squisq-page-radius); box-shadow: var(--squisq-page-shadow); }
1726
+ .squisq-page-table { width: 100%; border-collapse: collapse; font-size: 0.98rem; }
1727
+ .squisq-page-table th {
1728
+ background: var(--squisq-page-accent-bg);
1729
+ color: var(--squisq-page-accent-text);
1730
+ font-family: var(--squisq-page-title-font);
1731
+ text-align: left;
1732
+ padding: 0.8em 1em;
1733
+ }
1734
+ .squisq-page-table td { padding: 0.7em 1em; border-top: 1px solid var(--squisq-page-divider-color); }
1735
+ .squisq-page-table tbody tr:nth-child(even) { background: color-mix(in srgb, var(--squisq-page-text) 3.5%, transparent); }
1736
+
1737
+ /* \u2500\u2500 Canvas embed (spatial SVG) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1738
+ .squisq-page-canvas {
1739
+ width: 100%;
1740
+ margin-inline: auto;
1741
+ overflow: hidden;
1742
+ border-radius: var(--squisq-page-radius);
1743
+ }
1744
+ .squisq-page-canvas svg { display: block; width: 100%; height: 100%; }
1745
+ .squisq-page-canvas--framed { border: 1px solid var(--squisq-page-divider-color); box-shadow: var(--squisq-page-shadow); }
1746
+ .squisq-page-canvas--terminal { border: 1px solid color-mix(in srgb, var(--squisq-page-accent) 45%, transparent); }
1747
+ .squisq-page-canvas--terminal::before {
1748
+ content: '\\25CF \\25CF \\25CF';
1749
+ display: block;
1750
+ font-size: 9px;
1751
+ letter-spacing: 4px;
1752
+ padding: 6px 12px;
1753
+ color: color-mix(in srgb, var(--squisq-page-accent) 70%, transparent);
1754
+ background: color-mix(in srgb, var(--squisq-page-accent) 9%, var(--squisq-page-bg));
1755
+ border-bottom: 1px solid color-mix(in srgb, var(--squisq-page-accent) 30%, transparent);
1756
+ }
1757
+
1758
+ /* \u2500\u2500 Prose \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1759
+ .squisq-page-section--prose { padding-block: calc(var(--squisq-page-section-pad) * 0.45); }
1760
+ .squisq-page[data-divider] .squisq-page-section--prose + .squisq-page-section--prose { border-top: none; }
1761
+ .squisq-page-prose { font-size: 1.05rem; }
1762
+ .squisq-page-prose p { margin: 0; }
1763
+ .squisq-page-prose p + p { margin-top: 1.25em; }
1764
+ .squisq-page-prose > * + * { margin-top: 1.1em; }
1765
+ .squisq-page-prose a { color: var(--squisq-page-primary); text-decoration-color: color-mix(in srgb, var(--squisq-page-primary) 40%, transparent); }
1766
+ .squisq-page-prose code { font-family: var(--squisq-page-mono-font); font-size: 0.9em; background: color-mix(in srgb, var(--squisq-page-text) 8%, transparent); border-radius: 4px; padding: 0.12em 0.35em; }
1767
+ .squisq-page-prose pre { background: color-mix(in srgb, var(--squisq-page-text) 6%, transparent); border-radius: var(--squisq-page-radius); padding: 1em 1.25em; overflow-x: auto; }
1768
+ .squisq-page-prose pre code { background: none; padding: 0; }
1769
+ .squisq-page-prose blockquote { margin: 0; border-left: 4px solid var(--squisq-page-accent); padding-left: 1.25em; color: var(--squisq-page-text-muted); }
1770
+ .squisq-page-prose ul, .squisq-page-prose ol { padding-left: 1.5em; margin: 0; }
1771
+ .squisq-page-prose li + li { margin-top: 0.4em; }
1772
+ .squisq-page-prose hr { border: none; border-top: 1px solid var(--squisq-page-divider-color); }
1773
+ .squisq-page-prose table { width: 100%; border-collapse: collapse; }
1774
+ .squisq-page-prose th { font-family: var(--squisq-page-title-font); text-align: left; padding: 0.6em 0.8em; border-bottom: 2px solid var(--squisq-page-divider-color); }
1775
+ .squisq-page-prose td { padding: 0.55em 0.8em; border-bottom: 1px solid var(--squisq-page-divider-color); }
1776
+ .squisq-page-prose img { border-radius: var(--squisq-page-radius); }
1777
+ .squisq-page-prose h1, .squisq-page-prose h2, .squisq-page-prose h3,
1778
+ .squisq-page-prose h4, .squisq-page-prose h5, .squisq-page-prose h6 {
1779
+ font-family: var(--squisq-page-title-font);
1780
+ font-weight: var(--squisq-page-title-weight);
1781
+ line-height: 1.2;
1782
+ margin: 0 0 0.45em;
1783
+ }
1784
+ .squisq-page-prose h1 { font-size: 2.1rem; }
1785
+ .squisq-page-prose h2 { font-size: 1.65rem; }
1786
+ .squisq-page-prose h3 { font-size: 1.35rem; }
1787
+ .squisq-page-prose h4, .squisq-page-prose h5, .squisq-page-prose h6 { font-size: 1.15rem; }
1788
+ .squisq-page-section--prose[data-hint-drop-cap] .squisq-page-prose > p:first-child::first-letter {
1789
+ font-family: var(--squisq-page-title-font);
1790
+ font-size: 3.4em;
1791
+ font-weight: 700;
1792
+ float: left;
1793
+ line-height: 0.85;
1794
+ padding-right: 0.12em;
1795
+ color: var(--squisq-page-accent);
1796
+ }
1797
+
1798
+ /* \u2500\u2500 Footer band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1799
+ .squisq-page-section--footer { text-align: center; }
1800
+
1801
+ /* \u2500\u2500 Thin-margin embedding (chat bubbles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1802
+ .squisq-page--thin .squisq-page-section-inner { padding-inline: 0; }
1803
+ .squisq-page--thin .squisq-page-section { padding-block: 1.5rem; }
1804
+
1805
+ /* Thumbnail image mode */
1806
+ .squisq-page--thumbnail-images .squisq-page-prose img,
1807
+ .squisq-page--thumbnail-images .squisq-page-figure img { max-width: 100px; max-height: 100px; object-fit: cover; }
1808
+
1809
+ /* \u2500\u2500 Reveal animation (progressive enhancement) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1810
+ @media (prefers-reduced-motion: no-preference) {
1811
+ .squisq-page-reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.55s ease, transform 0.55s ease; }
1812
+ .squisq-page-reveal--in { opacity: 1; transform: none; }
1813
+ }
1814
+
1815
+ /* \u2500\u2500 Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1816
+ @container squisq-page (max-width: 720px) {
1817
+ ${NARROW_RULES}
1818
+ }
1819
+ @supports not (container-type: inline-size) {
1820
+ @media (max-width: 720px) {
1821
+ ${NARROW_RULES}
1822
+ }
1823
+ }
1824
+ `;
1825
+ function buildPageCss(theme) {
1826
+ const vars = buildPageCssVars(theme);
1827
+ const varLines = Object.entries(vars).map(([name, value]) => ` ${name}: ${value};`).join("\n");
1828
+ return `.squisq-page {
1829
+ ${varLines}
1830
+ }
1831
+ ${PAGE_BASE_CSS}`;
1832
+ }
1833
+
482
1834
  // src/doc/applyNarrationTiming.ts
483
1835
  var MIN_BLOCK_SIMILARITY = 0.5;
484
1836
  var MIN_V1_SCRIPT_SIMILARITY = 0.8;
485
1837
  var PIN_CONFLICT_TOLERANCE_SEC = 1;
486
1838
  function blockSpokenText(block) {
487
- const title = block.title ? block.title.trim() : "";
1839
+ const title2 = block.title ? block.title.trim() : "";
488
1840
  const body = getBlockBodyText(block);
489
- if (title && body) return `${title}
1841
+ if (title2 && body) return `${title2}
490
1842
  ${body}`;
491
- return title || body;
1843
+ return title2 || body;
492
1844
  }
493
1845
  function matchSidecarBlocks(flat, timing) {
494
1846
  const ranges = /* @__PURE__ */ new Map();
@@ -1131,8 +2483,8 @@ function checkAssets(markdownDoc, blocks, hasAsset, diagnostics) {
1131
2483
  }
1132
2484
  }
1133
2485
  const images = source["images"];
1134
- const list = typeof images === "string" ? images.split(",").map((s) => s.trim()) : Array.isArray(images) ? images.filter((i) => typeof i === "string") : [];
1135
- for (const img of list) {
2486
+ const list2 = typeof images === "string" ? images.split(",").map((s) => s.trim()) : Array.isArray(images) ? images.filter((i) => typeof i === "string") : [];
2487
+ for (const img of list2) {
1136
2488
  report(img, block.sourceHeading?.position?.start.line, block.id);
1137
2489
  }
1138
2490
  }
@@ -1157,16 +2509,16 @@ function truncate(text, max = 40) {
1157
2509
 
1158
2510
  // src/doc/asciiDiagram/render.ts
1159
2511
  var SIDE_MARGIN = 1;
1160
- function renderAsciiDiagram(diagram, options = {}) {
1161
- const vocab = (options.style ?? diagram.style) === "ascii" ? ASCII_VOCAB : UNICODE_VOCAB;
1162
- if (diagram.nodes.length === 0) return "";
1163
- const placed = layoutNodes(diagram.nodes, diagram.edges);
2512
+ function renderAsciiDiagram(diagram2, options = {}) {
2513
+ const vocab = (options.style ?? diagram2.style) === "ascii" ? ASCII_VOCAB : UNICODE_VOCAB;
2514
+ if (diagram2.nodes.length === 0) return "";
2515
+ const placed = layoutNodes(diagram2.nodes, diagram2.edges);
1164
2516
  const canvas = new Canvas();
1165
2517
  const drawOrder = [...placed.values()].sort(
1166
2518
  (a, b) => a.depth - b.depth || a.rect.r0 - b.rect.r0 || a.rect.c0 - b.rect.c0
1167
2519
  );
1168
2520
  for (const p of drawOrder) drawBox(canvas, p, vocab);
1169
- drawEdges(canvas, diagram.edges, placed, vocab);
2521
+ drawEdges(canvas, diagram2.edges, placed, vocab);
1170
2522
  return canvas.emit();
1171
2523
  }
1172
2524
  function computeSideDegrees(nodes, edges) {
@@ -1197,9 +2549,9 @@ function layoutNodes(nodes, edges) {
1197
2549
  const roots = [];
1198
2550
  for (const node of nodes) {
1199
2551
  if (node.containerId && byId.has(node.containerId) && node.containerId !== node.id) {
1200
- const list = childIds.get(node.containerId) ?? [];
1201
- list.push(node.id);
1202
- childIds.set(node.containerId, list);
2552
+ const list2 = childIds.get(node.containerId) ?? [];
2553
+ list2.push(node.id);
2554
+ childIds.set(node.containerId, list2);
1203
2555
  } else {
1204
2556
  roots.push(node.id);
1205
2557
  }
@@ -1366,12 +2718,12 @@ function drawBox(canvas, p, vocab) {
1366
2718
  const innerW = rect.c1 - rect.c0 - 1;
1367
2719
  canvas.set(rect.r0, rect.c0, vocab.tl, "border");
1368
2720
  canvas.set(rect.r0, rect.c1, vocab.tr, "border");
1369
- const title = isContainer && labelLines.length > 0 ? ` ${labelLines[0]} ` : null;
1370
- if (title && title.length <= innerW - 2) {
1371
- const left = Math.floor((innerW - title.length) / 2);
2721
+ const title2 = isContainer && labelLines.length > 0 ? ` ${labelLines[0]} ` : null;
2722
+ if (title2 && title2.length <= innerW - 2) {
2723
+ const left = Math.floor((innerW - title2.length) / 2);
1372
2724
  for (let i = 0; i < innerW; i++) {
1373
- const inTitle = i >= left && i < left + title.length;
1374
- const ch = inTitle ? title[i - left] : vocab.h;
2725
+ const inTitle = i >= left && i < left + title2.length;
2726
+ const ch = inTitle ? title2[i - left] : vocab.h;
1375
2727
  canvas.set(rect.r0, rect.c0 + 1 + i, ch, inTitle ? "label" : "border");
1376
2728
  }
1377
2729
  } else {
@@ -1497,10 +2849,10 @@ function assignAttachments(plans, placed) {
1497
2849
  ]);
1498
2850
  });
1499
2851
  const result = /* @__PURE__ */ new Map();
1500
- for (const [sideKey, list] of [...bySide.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
2852
+ for (const [sideKey, list2] of [...bySide.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
1501
2853
  const [nodeId, side] = sideKey.split("|");
1502
2854
  const node = placed.get(nodeId);
1503
- list.sort((a, b) => {
2855
+ list2.sort((a, b) => {
1504
2856
  const ra = placed.get(a.otherId).rect;
1505
2857
  const rb = placed.get(b.otherId).rect;
1506
2858
  return ra.r0 - rb.r0 || ra.c0 - rb.c0 || a.otherId.localeCompare(b.otherId);
@@ -1509,13 +2861,13 @@ function assignAttachments(plans, placed) {
1509
2861
  const from = horizontal ? node.rect.c0 + 1 : node.rect.r0 + 1;
1510
2862
  const to = horizontal ? node.rect.c1 - 1 : node.rect.r1 - 1;
1511
2863
  const inner = Math.max(1, to - from + 1);
1512
- const k = list.length;
2864
+ const k = list2.length;
1513
2865
  if (k === 1) {
1514
- result.set(list[0].key, { pos: from + Math.floor((inner - 1) / 2), index: 0, count: 1 });
2866
+ result.set(list2[0].key, { pos: from + Math.floor((inner - 1) / 2), index: 0, count: 1 });
1515
2867
  } else {
1516
2868
  const span = 2 * k - 1;
1517
2869
  const start = from + Math.max(0, Math.floor((inner - span) / 2));
1518
- list.forEach((req, i) => {
2870
+ list2.forEach((req, i) => {
1519
2871
  result.set(req.key, { pos: Math.min(to, start + 2 * i), index: i, count: k });
1520
2872
  });
1521
2873
  }
@@ -1848,8 +3200,8 @@ function repairAsciiDiagram(text) {
1848
3200
  const nodes = buildNodes(grid, rects);
1849
3201
  const edges = recoverEdges(grid, rects, nodes);
1850
3202
  const style = detectGridStyle(grid);
1851
- const diagram = { nodes, edges, style, warnings: ["repaired"] };
1852
- return { diagram, art: renderAsciiDiagram(diagram) };
3203
+ const diagram2 = { nodes, edges, style, warnings: ["repaired"] };
3204
+ return { diagram: diagram2, art: renderAsciiDiagram(diagram2) };
1853
3205
  }
1854
3206
  function dedupeRects(rects) {
1855
3207
  const seen = /* @__PURE__ */ new Set();
@@ -2090,10 +3442,10 @@ var MIN_AXIS_WIDTH = 48;
2090
3442
  var MAX_COORDINATE_AXIS_WIDTH = 64;
2091
3443
  var EVENT_SPACING = 3;
2092
3444
  var TERMINAL_RAIL_LENGTH = 3;
2093
- function renderAsciiTimeline(timeline, options = {}) {
2094
- const style = options.style ?? timeline.style;
3445
+ function renderAsciiTimeline(timeline2, options = {}) {
3446
+ const style = options.style ?? timeline2.style;
2095
3447
  const vocab = style === "ascii" ? ASCII_VOCAB2 : UNICODE_VOCAB2;
2096
- const { tracks, links } = prepareTimeline(timeline, style);
3448
+ const { tracks, links } = prepareTimeline(timeline2, style);
2097
3449
  if (tracks.length === 0) return "";
2098
3450
  const globalStart = Math.min(...tracks.map((track) => track.startColumn));
2099
3451
  const globalEnd = Math.max(...tracks.map((track) => track.endColumn));
@@ -2200,8 +3552,8 @@ function renderLink(link, style) {
2200
3552
  const arrow = style === "ascii" ? "->" : "\u2192";
2201
3553
  return `branch: ${link.source} ${arrow} ${link.target}${link.label ? ` : ${link.label}` : ""}`;
2202
3554
  }
2203
- function prepareTimeline(timeline, style) {
2204
- const sourceTracks = timeline.tracks.map((track, index) => ({ track, index })).filter(({ track }) => Array.isArray(track.events) && track.events.length > 0).sort(
3555
+ function prepareTimeline(timeline2, style) {
3556
+ const sourceTracks = timeline2.tracks.map((track, index) => ({ track, index })).filter(({ track }) => Array.isArray(track.events) && track.events.length > 0).sort(
2205
3557
  (a, b) => finiteOr(a.track.row, a.index) - finiteOr(b.track.row, b.index) || a.index - b.index || a.track.id.localeCompare(b.track.id)
2206
3558
  );
2207
3559
  const usedTrackIds = /* @__PURE__ */ new Set();
@@ -2260,7 +3612,7 @@ function prepareTimeline(timeline, style) {
2260
3612
  }
2261
3613
  const resolveEndpoint = (value) => endpointIds.get(value) ?? labelIds.get(slug(value));
2262
3614
  const links = [];
2263
- for (const link of Array.isArray(timeline.links) ? timeline.links : []) {
3615
+ for (const link of Array.isArray(timeline2.links) ? timeline2.links : []) {
2264
3616
  const source = resolveEndpoint(link.source);
2265
3617
  const target = resolveEndpoint(link.target);
2266
3618
  if (!source || !target) continue;
@@ -2318,8 +3670,8 @@ function formatCoordinate(value) {
2318
3670
  }
2319
3671
 
2320
3672
  // src/doc/treeview/render.ts
2321
- function renderTree(tree, options = {}) {
2322
- const vocab = (options.style ?? tree.style) === "ascii" ? ASCII_TREE_VOCAB : UNICODE_TREE_VOCAB;
3673
+ function renderTree(tree2, options = {}) {
3674
+ const vocab = (options.style ?? tree2.style) === "ascii" ? ASCII_TREE_VOCAB : UNICODE_TREE_VOCAB;
2323
3675
  const lines = [];
2324
3676
  const label = (node) => node.comment ? `${node.label} # ${node.comment}` : node.label;
2325
3677
  const walk = (nodes, prefix) => {
@@ -2329,7 +3681,7 @@ function renderTree(tree, options = {}) {
2329
3681
  walk(node.children, prefix + (last ? vocab.gap : vocab.rail));
2330
3682
  });
2331
3683
  };
2332
- for (const root of tree.roots) {
3684
+ for (const root of tree2.roots) {
2333
3685
  lines.push(label(root));
2334
3686
  walk(root.children, "");
2335
3687
  }
@@ -2344,6 +3696,16 @@ export {
2344
3696
  cssFilterForTreatment,
2345
3697
  docToMarkdown,
2346
3698
  resolveThemeForDoc,
3699
+ isTemplatedPageBlock,
3700
+ resolvePageBlock,
3701
+ sectionExtractors,
3702
+ resolvePageStyle,
3703
+ materializePageSection,
3704
+ materializePageSections,
3705
+ buildPageCssVars,
3706
+ pageStyleDataAttributes,
3707
+ PAGE_BASE_CSS,
3708
+ buildPageCss,
2347
3709
  applyNarrationTiming,
2348
3710
  scoreTextSimilarity,
2349
3711
  resolveAudioMapping,
@@ -2355,4 +3717,4 @@ export {
2355
3717
  renderAsciiTimeline,
2356
3718
  renderTree
2357
3719
  };
2358
- //# sourceMappingURL=chunk-QVANWDPH.js.map
3720
+ //# sourceMappingURL=chunk-OTKVFVL6.js.map