@sobree/core 0.1.2 → 0.1.3
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/doc/styles.d.ts +12 -0
- package/dist/doc/types.d.ts +28 -1
- package/dist/docx/export/contentTypes.d.ts +1 -0
- package/dist/docx/export/context.d.ts +1 -1
- package/dist/docx/export/numbering.d.ts +2 -0
- package/dist/docx/import/anchoredFrames.d.ts +4 -0
- package/dist/docx/import/borders.d.ts +12 -0
- package/dist/docx/import/floatFrames.d.ts +11 -0
- package/dist/docx/import/inlineFrames.d.ts +4 -0
- package/dist/docx/import/paragraphs.d.ts +6 -1
- package/dist/docx/import/styles.d.ts +13 -0
- package/dist/docx/shared/drawingColor.d.ts +30 -0
- package/dist/docx/types.d.ts +4 -0
- package/dist/editor/view/docRenderer/fontFallback.d.ts +18 -5
- package/dist/editor/view/docRenderer/inline.d.ts +2 -2
- package/dist/editor/view/docRenderer/lists.d.ts +22 -11
- package/dist/index.css +1 -1
- package/dist/index.js +4622 -4280
- package/dist/index.js.map +1 -1
- package/dist/ydoc/runs.d.ts +14 -18
- package/package.json +1 -1
package/dist/doc/styles.d.ts
CHANGED
|
@@ -17,3 +17,15 @@ export declare function resolveStyleCascade(styles: readonly NamedStyle[] | Sobr
|
|
|
17
17
|
runDefaults: RunProperties;
|
|
18
18
|
paragraphDefaults: ParagraphProperties;
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a RUN character style (`<w:rStyle>`) to the run properties it
|
|
22
|
+
* contributes: its own rPr merged up its `basedOn` chain — but WITHOUT
|
|
23
|
+
* the Normal / DocDefaults anchor that `resolveStyleCascade` appends.
|
|
24
|
+
*
|
|
25
|
+
* A character style layers on top of the run's INHERITED paragraph
|
|
26
|
+
* formatting; folding the document defaults back in here would reset the
|
|
27
|
+
* run's font / size to the doc default (e.g. a colour-only "Blue" char
|
|
28
|
+
* style must not drag Times/12pt onto a Helvetica/10pt contact line). So
|
|
29
|
+
* we walk only the explicit `basedOn` chain and stop — no Normal anchor.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveRunStyle(styles: readonly NamedStyle[], styleId: string): RunProperties;
|
package/dist/doc/types.d.ts
CHANGED
|
@@ -138,6 +138,20 @@ export interface AnchoredFrame {
|
|
|
138
138
|
* floats over text and reserves nothing. Absent ⇒ unknown (treated
|
|
139
139
|
* as non-displacing). */
|
|
140
140
|
wrap?: "square" | "topAndBottom" | "tight" | "through" | "none";
|
|
141
|
+
/** `wrapText` side from `<wp:wrapSquare|Tight|Through wrapText="…">` —
|
|
142
|
+
* which sides of the frame body text flows on. Default `bothSides`.
|
|
143
|
+
* Only meaningful for the displacing wrap modes; drives whether a
|
|
144
|
+
* floated image goes `float: left` (text on the right) or `right`. */
|
|
145
|
+
wrapText?: "bothSides" | "left" | "right" | "largest";
|
|
146
|
+
/** Text-distance insets — `distT/B/L/R` on `<wp:anchor>`, in EMU. The
|
|
147
|
+
* gap Word keeps between the frame and the text wrapping around it;
|
|
148
|
+
* rendered as margins on the floated frame. */
|
|
149
|
+
textDistancesEmu?: {
|
|
150
|
+
topEmu: number;
|
|
151
|
+
rightEmu: number;
|
|
152
|
+
bottomEmu: number;
|
|
153
|
+
leftEmu: number;
|
|
154
|
+
};
|
|
141
155
|
/** What this frame contains. */
|
|
142
156
|
content: AnchoredContent;
|
|
143
157
|
}
|
|
@@ -453,10 +467,23 @@ export interface DrawingRun {
|
|
|
453
467
|
* - "inline" — flows in the paragraph like a tall character.
|
|
454
468
|
* - "anchor" — positioned absolutely (`<wp:anchor>`); `anchor`
|
|
455
469
|
* carries the offset + frame-of-reference.
|
|
470
|
+
* - "floatLeft" / "floatRight" — a `<wp:anchor>` image with a
|
|
471
|
+
* displacing wrap (square/tight/through), converted to a
|
|
472
|
+
* CSS float at the head of its anchor paragraph so body
|
|
473
|
+
* text flows around it. `floatMarginsEmu` carries the
|
|
474
|
+
* `distT/B/L/R` clearance.
|
|
456
475
|
*/
|
|
457
|
-
placement: "inline" | "anchor";
|
|
476
|
+
placement: "inline" | "anchor" | "floatLeft" | "floatRight";
|
|
458
477
|
/** Set when `placement === "anchor"`. */
|
|
459
478
|
anchor?: DrawingAnchor;
|
|
479
|
+
/** Set for `floatLeft` / `floatRight` — the text-clearance margins
|
|
480
|
+
* (from the frame's `distT/B/L/R`), applied as CSS margins. */
|
|
481
|
+
floatMarginsEmu?: {
|
|
482
|
+
topEmu: number;
|
|
483
|
+
rightEmu: number;
|
|
484
|
+
bottomEmu: number;
|
|
485
|
+
leftEmu: number;
|
|
486
|
+
};
|
|
460
487
|
/**
|
|
461
488
|
* Vertical alignment for an `inline` image relative to the text on
|
|
462
489
|
* its line. Defaults to the browser baseline (image bottom on the
|
|
@@ -4,6 +4,7 @@ declare const REL_TYPES: {
|
|
|
4
4
|
readonly image: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
5
5
|
readonly hyperlink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
6
6
|
readonly fontTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
|
|
7
|
+
readonly numbering: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
|
|
7
8
|
readonly font: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font";
|
|
8
9
|
};
|
|
9
10
|
type RelKind = keyof typeof REL_TYPES;
|
|
@@ -13,7 +13,7 @@ export interface ExportContext {
|
|
|
13
13
|
/** Rels to append to `word/_rels/document.xml.rels`. */
|
|
14
14
|
relationships: Array<{
|
|
15
15
|
id: string;
|
|
16
|
-
type: "header" | "footer" | "image" | "hyperlink" | "fontTable";
|
|
16
|
+
type: "header" | "footer" | "image" | "hyperlink" | "fontTable" | "numbering";
|
|
17
17
|
target: string;
|
|
18
18
|
/** External targets (URLs) need `TargetMode="External"`. */
|
|
19
19
|
external?: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AnchoredFrame, Block } from '../../doc/types';
|
|
2
|
+
import { ThemePalette } from '../shared/drawingColor';
|
|
2
3
|
export interface AnchoredFramesContext {
|
|
3
4
|
/** RelationshipId → part path lookup, e.g. `"rId4" → "media/image1.png"`. */
|
|
4
5
|
rels: Map<string, string>;
|
|
@@ -20,6 +21,9 @@ export interface AnchoredFramesContext {
|
|
|
20
21
|
* its true layout. When absent, falls back to flat text (tests).
|
|
21
22
|
*/
|
|
22
23
|
parseBlockBody?: (txbxContent: Element) => Block[];
|
|
24
|
+
/** Theme colour palette (from `word/theme/theme1.xml`) so shape fills /
|
|
25
|
+
* strokes declared as `<a:schemeClr>` resolve instead of vanishing. */
|
|
26
|
+
theme?: ThemePalette;
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
25
29
|
* Walk every `<w:drawing>/<wp:anchor>` in the document and return one
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ParagraphBorders } from '../../doc/types';
|
|
2
|
+
/**
|
|
3
|
+
* Read a `<w:pBdr>` paragraph-border element into `ParagraphBorders`.
|
|
4
|
+
*
|
|
5
|
+
* Shared by the direct-paragraph parser AND the named-style parser: Word
|
|
6
|
+
* puts the divider rules of letterhead / résumé headers on a STYLE (e.g. a
|
|
7
|
+
* "Name" style's `<w:top>` rule), not on each paragraph. Reading it only
|
|
8
|
+
* for direct paragraphs dropped those rules entirely (the renderer's
|
|
9
|
+
* `effective.borders` cascade had nothing to apply). `none` / `nil` sides
|
|
10
|
+
* are skipped (Word's explicit "no border on this side").
|
|
11
|
+
*/
|
|
12
|
+
export declare function readParagraphBorders(pPr: Element): ParagraphBorders | undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnchoredFrame, Block, SectionProperties } from '../../doc/types';
|
|
2
|
+
/**
|
|
3
|
+
* Prepend a float `DrawingRun` to each floatable frame's anchor paragraph
|
|
4
|
+
* and drop those frames from the overlay set. Pure — inputs untouched.
|
|
5
|
+
* Body indices are stable (we modify paragraphs in place, never insert),
|
|
6
|
+
* so it composes after `flowDisplacingTextboxes` without an index remap.
|
|
7
|
+
*/
|
|
8
|
+
export declare function floatWrappingImages(body: readonly Block[], frames: readonly AnchoredFrame[], sections: readonly SectionProperties[]): {
|
|
9
|
+
body: Block[];
|
|
10
|
+
frames: AnchoredFrame[];
|
|
11
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Block, InlineFrame } from '../../doc/types';
|
|
2
|
+
import { ThemePalette } from '../shared/drawingColor';
|
|
2
3
|
export interface InlineFramesContext {
|
|
3
4
|
/** RelationshipId → part path lookup. */
|
|
4
5
|
rels: Map<string, string>;
|
|
@@ -26,6 +27,9 @@ export interface InlineFramesContext {
|
|
|
26
27
|
* Without this flag, only explicit directives count.
|
|
27
28
|
*/
|
|
28
29
|
honorLastRenderedPageBreaks?: boolean;
|
|
30
|
+
/** Theme colour palette (from `word/theme/theme1.xml`) so textbox /
|
|
31
|
+
* shape fills declared as `<a:schemeClr>` resolve instead of vanishing. */
|
|
32
|
+
theme?: ThemePalette;
|
|
29
33
|
}
|
|
30
34
|
/**
|
|
31
35
|
* One InlineFrame plus the source DOM nodes it came from.
|
|
@@ -4,9 +4,14 @@ import { ParagraphFormat } from '../types';
|
|
|
4
4
|
export type ImportedItem = {
|
|
5
5
|
kind: "run";
|
|
6
6
|
run: ImportedRun;
|
|
7
|
-
}
|
|
7
|
+
}
|
|
8
|
+
/** `href` is set for HYPERLINK *fields* (the target lives in the field
|
|
9
|
+
* instruction); `relId` for `<w:hyperlink r:id>` elements (resolved
|
|
10
|
+
* against the rels table downstream). */
|
|
11
|
+
| {
|
|
8
12
|
kind: "hyperlink";
|
|
9
13
|
relId?: string;
|
|
14
|
+
href?: string;
|
|
10
15
|
runs: ImportedRun[];
|
|
11
16
|
};
|
|
12
17
|
export interface ImportedParagraph {
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import { NamedStyle } from '../../doc/types';
|
|
2
2
|
import { DocSettings } from './settings';
|
|
3
|
+
/**
|
|
4
|
+
* Canonicalise a heading style id to `HeadingN`.
|
|
5
|
+
*
|
|
6
|
+
* Word and OpenOffice name the heading styles inconsistently across docs:
|
|
7
|
+
* `Heading2`, `Heading 2`, `heading 2`. The paragraph importer already
|
|
8
|
+
* maps a heading PARAGRAPH's styleId to the canonical `HeadingN` (so it
|
|
9
|
+
* renders as `<hN>` and joins the `HeadingN` convention used by builders /
|
|
10
|
+
* serialize / markdown). The STYLE definition must canonicalise the same
|
|
11
|
+
* way, or `resolveStyleCascade` looks up `HeadingN` and misses the
|
|
12
|
+
* actual style — dropping its colour, caps, etc. Non-heading ids pass
|
|
13
|
+
* through unchanged.
|
|
14
|
+
*/
|
|
15
|
+
export declare function canonicalStyleId(id: string): string;
|
|
3
16
|
export declare function parseStylesXml(xml: string | undefined, settings?: DocSettings): NamedStyle[] | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DrawingML colour resolution — literal AND theme colours.
|
|
3
|
+
*
|
|
4
|
+
* A DrawingML colour container (`<a:solidFill>`, the children of
|
|
5
|
+
* `<a:ln>`, …) holds either a literal `<a:srgbClr val="RRGGBB">` or a
|
|
6
|
+
* theme reference `<a:schemeClr val="accent1">`. Both can carry child
|
|
7
|
+
* TRANSFORM elements that adjust the base colour (`hueOff`, `satOff`,
|
|
8
|
+
* `lumOff`, `lumMod`, `shade`, `tint`, …). Word resolves the scheme slot
|
|
9
|
+
* against `word/theme/theme1.xml`'s `<a:clrScheme>` and applies the
|
|
10
|
+
* transforms in document order — reading only `srgbClr` renders every
|
|
11
|
+
* theme-coloured shape invisible (no fill, no stroke).
|
|
12
|
+
*
|
|
13
|
+
* Transform units (ECMA-376 §20.1.2.3):
|
|
14
|
+
* - `hueOff` — 60000ths of a degree, added to the hue.
|
|
15
|
+
* - `satOff` / `lumOff` — 1000ths of a percent-POINT, added to S / L.
|
|
16
|
+
* - `satMod` / `lumMod` — 100000ths, multiplied onto S / L.
|
|
17
|
+
* - `shade` — scale toward black (val/100000).
|
|
18
|
+
* - `tint` — scale toward white (val/100000).
|
|
19
|
+
*/
|
|
20
|
+
/** Theme slot → `#RRGGBB`. Slots: dk1/lt1/dk2/lt2/accent1-6/hlink/folHlink. */
|
|
21
|
+
export type ThemePalette = Record<string, string>;
|
|
22
|
+
/** Parse `word/theme/theme1.xml` into the colour-scheme palette.
|
|
23
|
+
* Returns undefined when the part is absent or malformed. */
|
|
24
|
+
export declare function parseThemeXml(xml: string | undefined): ThemePalette | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the colour child of `parent` (an `<a:solidFill>` or `<a:ln>`-
|
|
27
|
+
* style container): literal `srgbClr` or theme `schemeClr`, transforms
|
|
28
|
+
* applied. Returns `#RRGGBB` or undefined when no resolvable colour.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readDrawingColor(parent: Element, theme?: ThemePalette): string | undefined;
|
package/dist/docx/types.d.ts
CHANGED
|
@@ -18,6 +18,10 @@ export interface DocxExportResult {
|
|
|
18
18
|
}
|
|
19
19
|
/** A single inline run's formatting flags — what `<w:rPr>` tells us. */
|
|
20
20
|
export interface RunFormat {
|
|
21
|
+
/** `<w:rStyle w:val="…">` — a character style applied to the run. Its
|
|
22
|
+
* rPr (colour, underline, …) is resolved against the style cascade at
|
|
23
|
+
* render time, under any direct run formatting. */
|
|
24
|
+
styleId?: string;
|
|
21
25
|
bold?: boolean;
|
|
22
26
|
italic?: boolean;
|
|
23
27
|
underline?: boolean;
|
|
@@ -19,10 +19,23 @@
|
|
|
19
19
|
* `pnpm fixtures:compare --pages` on user-contract.docx (Bookman not
|
|
20
20
|
* installed on macOS by default). See [diagnosis notes].
|
|
21
21
|
*/
|
|
22
|
+
/** A face name resolved for CSS: the family fallback stack, plus the
|
|
23
|
+
* weight / italic the face name implied (absent when the name carried
|
|
24
|
+
* no face tokens — the run's own bold/italic then fully decide). */
|
|
25
|
+
export interface ResolvedFontFace {
|
|
26
|
+
stack: string;
|
|
27
|
+
weight?: number;
|
|
28
|
+
italic?: boolean;
|
|
29
|
+
}
|
|
22
30
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
31
|
+
* Resolve an OOXML font NAME into a CSS family stack + implied weight.
|
|
32
|
+
*
|
|
33
|
+
* Curated whole-name chains win first ("Calibri Light" is a real family
|
|
34
|
+
* with its own calibrated chain — corpus baselines depend on it). Then
|
|
35
|
+
* trailing face tokens are stripped ("Helvetica Neue Light" → base
|
|
36
|
+
* "Helvetica Neue" + weight 300) and the BASE resolves through the same
|
|
37
|
+
* curated chains; the full face name stays first in the stack so hosts
|
|
38
|
+
* that do ship the exact face still use it. A name with no tokens and no
|
|
39
|
+
* curated chain keeps the documented unknown-font default (`, serif`).
|
|
27
40
|
*/
|
|
28
|
-
export declare function
|
|
41
|
+
export declare function resolveFontFace(fontFamily: string): ResolvedFontFace;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InlineRun } from '../../../doc/types';
|
|
1
|
+
import { InlineRun, NamedStyle } from '../../../doc/types';
|
|
2
2
|
/**
|
|
3
3
|
* Render a list of InlineRuns into DOM children of `parent`. Empty run
|
|
4
4
|
* lists produce a `<br>` placeholder so contenteditable can place a
|
|
@@ -7,7 +7,7 @@ import { InlineRun } from '../../../doc/types';
|
|
|
7
7
|
* `rawParts` is threaded through so `DrawingRun` can resolve its
|
|
8
8
|
* `partPath` to an `<img src>` via a blob URL / data URI.
|
|
9
9
|
*/
|
|
10
|
-
export declare function appendInlineRuns(parent: HTMLElement, runs: readonly InlineRun[], rawParts?: Record<string, Uint8Array
|
|
10
|
+
export declare function appendInlineRuns(parent: HTMLElement, runs: readonly InlineRun[], rawParts?: Record<string, Uint8Array>, styles?: readonly NamedStyle[]): void;
|
|
11
11
|
/** Convert a raw part's bytes (from `doc.rawParts`) into a blob URL
|
|
12
12
|
* the browser can render as `<img src>` / `background-image`. Exported
|
|
13
13
|
* for the section-frame renderer in `block.ts` which paints the
|
|
@@ -2,16 +2,27 @@ import { Block, NumberingDefinition } from '../../../doc/types';
|
|
|
2
2
|
export interface ListInfo {
|
|
3
3
|
numId: number;
|
|
4
4
|
ordered: boolean;
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
* Applied as `padding-left` on the OL / UL so wrapped text lands at
|
|
8
|
-
* the right position and the marker hangs to its left. */
|
|
5
|
+
/** Text-column indent (`<w:ind w:left>`), twips → the OL/UL
|
|
6
|
+
* `padding-left`. First line and wraps both align here. */
|
|
9
7
|
leftTwips?: number;
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
8
|
+
/** Marker hang (`<w:ind w:hanging>`), twips → the width of the
|
|
9
|
+
* `::before` marker box; the marker sits at `leftTwips - hangingTwips`. */
|
|
12
10
|
hangingTwips?: number;
|
|
13
|
-
/**
|
|
11
|
+
/** Bullet glyph (post-Wingdings remapping), for unordered lists. */
|
|
14
12
|
bulletGlyph?: string;
|
|
13
|
+
/** Marker glyph's own run formatting (`<w:lvl><w:rPr>`): colour, font,
|
|
14
|
+
* size. The font also matters for layout — Word lets the marker
|
|
15
|
+
* font's strut set the bullet line height (see paperStack.css). */
|
|
16
|
+
markerColor?: string;
|
|
17
|
+
markerFont?: string;
|
|
18
|
+
markerSizePt?: number;
|
|
19
|
+
/** CSS counter-style class suffix for ordered lists (`decimal`,
|
|
20
|
+
* `lower-latin`, …) — selects the matching `::before` rule. */
|
|
21
|
+
counterStyle?: string;
|
|
22
|
+
/** Literal text around the number in `lvlText` (`%1.` → suffix `.`;
|
|
23
|
+
* `(%1)` → prefix `(`, suffix `)`). */
|
|
24
|
+
markerPrefix?: string;
|
|
25
|
+
markerSuffix?: string;
|
|
15
26
|
}
|
|
16
27
|
/**
|
|
17
28
|
* Resolve a paragraph's list membership from the numbering table.
|
|
@@ -20,9 +31,9 @@ export interface ListInfo {
|
|
|
20
31
|
*/
|
|
21
32
|
export declare function paragraphListInfo(block: Block, numbering: readonly NumberingDefinition[]): ListInfo | null;
|
|
22
33
|
/**
|
|
23
|
-
* Build the `<ol>` / `<ul>` container for a run of list items sharing
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
34
|
+
* Build the `<ol>` / `<ul>` container for a run of list items sharing a
|
|
35
|
+
* `numId`. Sets the text-column `padding-left`, the `--sobree-list-hang`
|
|
36
|
+
* marker-box width, and the marker content (glyph or counter format) the
|
|
37
|
+
* CSS `::before` rules consume.
|
|
27
38
|
*/
|
|
28
39
|
export declare function createListContainer(info: ListInfo, sectionIndex: number): HTMLElement;
|
package/dist/index.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.paper-stack{display:flex;flex-direction:column;padding:48px;gap:28px;outline:none}.paper-row{display:flex;flex-direction:row;align-items:flex-start;gap:24px}.paper{position:relative;background:#fff;border:1px solid rgba(0,0,0,.3);box-shadow:0 1px 2px #00000014,0 18px 60px #0000001f;padding-top:var(--margin-top, 25mm);padding-right:var(--margin-right, 20mm);padding-bottom:var(--margin-bottom, 25mm);padding-left:var(--margin-left, 20mm);overflow:hidden;flex:none}.paper-header,.paper-footer{position:absolute;left:var(--margin-left, 20mm);right:var(--margin-right, 20mm);font-size:10pt;color:#555;white-space:pre-wrap}.paper-header{top:0;min-height:var(--margin-top, 25mm);padding-top:var(--header-offset-mm, 12.7mm);padding-bottom:4mm;border-bottom:1px dashed transparent}.paper-footer{bottom:0;min-height:var(--margin-bottom, 25mm);padding-top:4mm;text-align:center;border-top:1px dashed transparent}.paper-anchors{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;isolation:isolate;z-index:1}.paper-anchors.is-empty{display:none}.paper-zone-anchors{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;isolation:isolate;z-index:2}.paper-zone-anchors.is-empty{display:none}.paper-anchor{position:absolute;box-sizing:border-box;overflow:hidden}.paper-header>p,.paper-footer>p,.paper-header>ul,.paper-header>ol,.paper-footer>ul,.paper-footer>ol{margin:0}.paper-footnotes{position:absolute;left:var(--margin-left, 20mm);right:var(--margin-right, 20mm);bottom:var(--margin-bottom, 25mm);font-size:.85em;padding-top:.5em;border-top:1pt solid currentColor;background:#fffffff5;z-index:1;max-height:40%;overflow:hidden}.paper-footnotes.is-empty{display:none}.paper-comments{flex:0 0 70mm;max-width:70mm;font-size:.85em;padding:0 .5em;align-self:stretch;overflow-y:auto}.paper-comments.is-empty{display:none}.paper-footnotes .sobree-footnotes__list{margin:0;padding-left:1.5em}.paper-footnotes .sobree-footnotes__item{margin:.25em 0}.paper-content{position:relative;height:100%;min-height:100px;display:
|
|
1
|
+
.paper-stack{display:flex;flex-direction:column;padding:48px;gap:28px;outline:none}.paper-row{display:flex;flex-direction:row;align-items:flex-start;gap:24px}.paper{position:relative;background:#fff;border:1px solid rgba(0,0,0,.3);box-shadow:0 1px 2px #00000014,0 18px 60px #0000001f;padding-top:var(--margin-top, 25mm);padding-right:var(--margin-right, 20mm);padding-bottom:var(--margin-bottom, 25mm);padding-left:var(--margin-left, 20mm);overflow:hidden;flex:none}.paper-header,.paper-footer{position:absolute;left:var(--margin-left, 20mm);right:var(--margin-right, 20mm);font-size:10pt;color:#555;white-space:pre-wrap}.paper-header{top:0;min-height:var(--margin-top, 25mm);padding-top:var(--header-offset-mm, 12.7mm);padding-bottom:4mm;border-bottom:1px dashed transparent}.paper-footer{bottom:0;min-height:var(--margin-bottom, 25mm);padding-top:4mm;text-align:center;border-top:1px dashed transparent}.paper-anchors{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;isolation:isolate;z-index:1}.paper-anchors.is-empty{display:none}.paper-zone-anchors{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;isolation:isolate;z-index:2}.paper-zone-anchors.is-empty{display:none}.paper-anchor{position:absolute;box-sizing:border-box;overflow:hidden}.paper-header>p,.paper-footer>p,.paper-header>ul,.paper-header>ol,.paper-footer>ul,.paper-footer>ol{margin:0}.paper-footnotes{position:absolute;left:var(--margin-left, 20mm);right:var(--margin-right, 20mm);bottom:var(--margin-bottom, 25mm);font-size:.85em;padding-top:.5em;border-top:1pt solid currentColor;background:#fffffff5;z-index:1;max-height:40%;overflow:hidden}.paper-footnotes.is-empty{display:none}.paper-comments{flex:0 0 70mm;max-width:70mm;font-size:.85em;padding:0 .5em;align-self:stretch;overflow-y:auto}.paper-comments.is-empty{display:none}.paper-footnotes .sobree-footnotes__list{margin:0;padding-left:1.5em}.paper-footnotes .sobree-footnotes__item{margin:.25em 0}.paper-content a{color:inherit;text-decoration:none}.paper-content{position:relative;height:100%;min-height:100px;display:flow-root}.paper-content td p:not([style*=line-height]),.paper-content td li:not([style*=line-height]),.paper-content th p:not([style*=line-height]),.paper-content th li:not([style*=line-height]){line-height:1}.paper-content td p:not([style*=margin]),.paper-content th p:not([style*=margin]){margin:0}.paper-content .sobree-hang>li{list-style:none}.paper-content .sobree-hang>li:before{display:inline-block;box-sizing:border-box;width:var(--sobree-list-hang, 0);margin-left:calc(-1 * var(--sobree-list-hang, 0));white-space:nowrap;color:var(--sobree-marker-color, currentColor);font-family:var(--sobree-marker-font, inherit);font-size:var(--sobree-marker-size, inherit)}.paper-content .sobree-hang.lst-bullet>li:before{content:var(--sobree-bullet, "•")}.paper-content .sobree-hang.lst-decimal>li:before{content:var(--mk-pre, "") counter(list-item,decimal) var(--mk-suf, ".")}.paper-content .sobree-hang.lst-decimal-zero>li:before{content:var(--mk-pre, "") counter(list-item,decimal-leading-zero) var(--mk-suf, ".")}.paper-content .sobree-hang.lst-lower-latin>li:before{content:var(--mk-pre, "") counter(list-item,lower-latin) var(--mk-suf, ".")}.paper-content .sobree-hang.lst-upper-latin>li:before{content:var(--mk-pre, "") counter(list-item,upper-latin) var(--mk-suf, ".")}.paper-content .sobree-hang.lst-lower-roman>li:before{content:var(--mk-pre, "") counter(list-item,lower-roman) var(--mk-suf, ".")}.paper-content .sobree-hang.lst-upper-roman>li:before{content:var(--mk-pre, "") counter(list-item,upper-roman) var(--mk-suf, ".")}.paper-content .sobree-tab-spread{display:flex;justify-content:space-between;align-items:baseline;gap:1em;white-space:nowrap}.paper-content .sobree-tab-spread .sobree-tab-spread__before,.paper-content .sobree-tab-spread .sobree-tab-spread__after{white-space:pre-wrap;min-width:0}.paper-content table.sobree-table-bordered td,.paper-content table.sobree-table-bordered th{border:var(--table-cell-border, none);padding:0 4px}.sobree-editor{position:relative;outline:none}.sobree-editor>:first-child{margin-top:0}.sobree-editor p,.sobree-editor h1,.sobree-editor h2,.sobree-editor h3,.sobree-editor h4,.sobree-editor h5,.sobree-editor h6,.sobree-editor ul,.sobree-editor ol,.sobree-editor li,.sobree-editor blockquote,.sobree-editor pre{margin:0;padding:0}.sobree-editor ul,.sobree-editor ol{padding-left:1.5em}.sobree-editor li.sobree-li-continuation{list-style-type:none}.sobree-editor li.sobree-li-continuation::marker{content:""}.sobree-editor .sobree-fragment-continued{text-align-last:justify}.sobree-editor .sobree-footnote-ref a{color:inherit;text-decoration:none}.sobree-editor .sobree-footnote-ref a:hover{text-decoration:underline}.sobree-editor .sobree-footnotes{margin-top:2em;padding-top:.5em;border-top:1pt solid currentColor;font-size:.85em}.sobree-editor .sobree-footnotes__list{padding-left:1.5em}.sobree-editor .sobree-footnotes__item{margin:.25em 0}.sobree-editor ins.sobree-revision-ins{text-decoration:underline}.sobree-editor del.sobree-revision-del{text-decoration:line-through}.sobree-editor .sobree-revision-format{text-decoration:underline dashed var(--sobree-format-revision-color, currentColor);text-underline-offset:3px}.sobree-editor [data-block-revision=ins]:after,.sobree-editor [data-block-revision=del]:after{content:" ¶";color:var(--sobree-block-revision-color, currentColor);opacity:.65;font-weight:600;-webkit-user-select:none;user-select:none}.sobree-editor [data-block-revision=del]:after{text-decoration:line-through}.sobree-editor .sobree-comment-range{background:var(--sobree-comment-range-bg, rgba(255, 217, 0, .25));border-bottom:1px dotted var(--sobree-comment-range-border, rgba(180, 130, 0, .5))}.sobree-editor .sobree-comment-ref{display:inline;font-size:.85em;margin:0 .1em}.sobree-editor .sobree-comment-ref a{color:inherit;text-decoration:none}.sobree-editor .sobree-comment-ref a:hover{filter:brightness(.7)}.sobree-editor h1,.sobree-editor h2,.sobree-editor h3,.sobree-editor h4,.sobree-editor h5,.sobree-editor h6{font-size:inherit;font-weight:inherit}.sobree-editor table{border-collapse:collapse;width:100%;position:relative}.sobree-editor th,.sobree-editor td{border:none;padding:0 .08in;vertical-align:top;transition:border-color .12s ease}.sobree-editor .sobree-section-break{display:flex;align-items:center;gap:8px;margin:8px 0;color:var(--fg-subtle, #7c7764);font-size:11px;letter-spacing:.04em;text-transform:uppercase;-webkit-user-select:none;user-select:none}.sobree-editor .sobree-section-break--continuous{visibility:hidden;height:0;margin:0;padding:0;border:none;overflow:hidden;font-size:0;line-height:0}.sobree-editor .sobree-section-break:before,.sobree-editor .sobree-section-break:after{content:"";flex:1;border-top:1px dashed var(--border, #dedbd0)}.sobree-editor .sobree-section-break__label{flex:none;padding:0 6px;background:var(--bg-elevated, #fff)}.sobree-editor .sobree-textbox-frame p{line-height:1.2}.sobree-editor .paper-content p,.sobree-editor .paper-content li,.sobree-editor .paper-header p,.sobree-editor .paper-header li,.sobree-editor .paper-footer p,.sobree-editor .paper-footer li,.sobree-editor .sobree-textbox-frame p{white-space:pre-wrap}.sobree-editor .sobree-section-trailer-empty{height:0;line-height:0;font-size:0;margin:0;padding:0;overflow:hidden}.sobree-editor .sobree-textbox-frame--placeholder{border:1px solid var(--border, #c8c4b8)}.sobree-editor .sobree-textbox-frame--placeholder.sobree-textbox-frame--filled{border:none;z-index:-1}.sobree-editor img.is-selected{outline:2px solid var(--sobree-primary, #d4521f);outline-offset:2px}.sobree-image-resize-handle{position:absolute;width:16px;height:16px;background:var(--sobree-primary, #d4521f);border:2px solid #fff;border-radius:3px;cursor:nwse-resize;z-index:1000;-webkit-user-select:none;user-select:none}.sobree-viewport{position:relative;overflow:hidden;overscroll-behavior:contain;touch-action:none;background:#ececee}.sobree-viewport__stage{position:absolute;top:0;left:0;transform-origin:0 0;will-change:transform}.sobree-viewport__stage.is-animating{transition:transform .32s cubic-bezier(.2,.7,.2,1)}.sobree-viewport__slot{display:block}.paper-stack .paper-content,.paper-stack .paper-header,.paper-stack .paper-footer{transition:opacity .2s ease}.paper-stack.is-zone-editing .paper-content,.paper-stack.is-zone-editing .paper-header,.paper-stack.is-zone-editing .paper-footer{opacity:.2}.paper-stack.is-zone-editing .paper-header[contenteditable=true],.paper-stack.is-zone-editing .paper-footer[contenteditable=true]{opacity:1}.paper-header[contenteditable=true],.paper-footer[contenteditable=true]{outline:2px dotted var(--primary, #c96f22);outline-offset:4px;background:var(--primary-soft, #fdf6ee);color:var(--fg-strong, #14130f);border-radius:2px}
|