diff --git a/CHANGELOG.md b/CHANGELOG.md index 35441123d..111f047b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,22 @@ follow semantic versioning; release dates are ISO 8601. ### Templates +- **A second structured proposal preset: `EditorialProposal`.** The same document the + `NorthlineProposal` preset renders, in a different hand: an orange accent, section + headings set in the display serif over short accent rules instead of in the body sans + inside icon badges, a brand mark drawn from vector paths instead of a monogram letter, + an untitled fact card, a scope ordinal set in plain accent text, and a hairline page + foot. Moving a document between the two presets is a one-line change plus two data + checks — the badge and goal icon tokens are preset-scoped (the four `fact-*` tokens + are not), and headings are drawn as authored, so the sibling's tracked capitals stay + capitals here. Ships as + `proposal.presets.EditorialProposal` on the structured proposal model, porting the + rendered layout of the published standalone `northline-proposal-orange` template, + with its SVG icon set packaged in the artifact. Guarded by a smoke test (including + the empty document, both data contracts, and the proof that one document renders + through both proposal presets), an exact two-page layout snapshot, and a + pixel-parity gate; the examples showcase gains `proposal-editorial-v2`. + - **A professional-services invoice preset: `ConsultingInvoice`.** A corporate masthead — brand lockup and contact channels beside the document title and its metadata — over priced service lines that carry a service period and a unit per line, closing diff --git a/assets/readme/examples/proposal-editorial-v2.pdf b/assets/readme/examples/proposal-editorial-v2.pdf new file mode 100644 index 000000000..03baf9ce2 Binary files /dev/null and b/assets/readme/examples/proposal-editorial-v2.pdf differ diff --git a/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java b/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java index f70158ec1..0032601a4 100644 --- a/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java +++ b/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java @@ -101,6 +101,7 @@ import com.demcha.examples.templates.invoice.InvoiceCinematicFileExample; import com.demcha.examples.templates.invoice.ModernInvoiceV2Example; import com.demcha.examples.templates.proposal.CinematicProposalFileExample; +import com.demcha.examples.templates.proposal.EditorialProposalV2Example; import com.demcha.examples.templates.proposal.NorthlineProposalV2Example; import com.demcha.examples.templates.proposal.ProposalCinematicFileExample; import com.demcha.examples.templates.proposal.ModernProposalV2Example; @@ -172,6 +173,7 @@ public static void main(String[] args) throws Exception { System.out.println("Generated: " + ProposalCinematicFileExample.generate()); System.out.println("Generated: " + ModernProposalV2Example.generate()); System.out.println("Generated: " + NorthlineProposalV2Example.generate()); + System.out.println("Generated: " + EditorialProposalV2Example.generate()); System.out.println("Generated: " + CinematicProposalFileExample.generate()); // Schedule diff --git a/examples/src/main/java/com/demcha/examples/support/EditorialProposalSampleData.java b/examples/src/main/java/com/demcha/examples/support/EditorialProposalSampleData.java new file mode 100644 index 000000000..343a08e61 --- /dev/null +++ b/examples/src/main/java/com/demcha/examples/support/EditorialProposalSampleData.java @@ -0,0 +1,147 @@ +package com.demcha.examples.support; + +import com.demcha.compose.document.templates.data.proposal.ProposalAcceptance; +import com.demcha.compose.document.templates.data.proposal.ProposalBrand; +import com.demcha.compose.document.templates.data.proposal.ProposalDeliverables; +import com.demcha.compose.document.templates.data.proposal.ProposalGlance; +import com.demcha.compose.document.templates.data.proposal.ProposalGoals; +import com.demcha.compose.document.templates.data.proposal.ProposalInvestment; +import com.demcha.compose.document.templates.data.proposal.ProposalMetaLine; +import com.demcha.compose.document.templates.data.proposal.ProposalPhaseGrid; +import com.demcha.compose.document.templates.data.proposal.ProposalScope; +import com.demcha.compose.document.templates.data.proposal.ProposalSummaryBlock; +import com.demcha.compose.document.templates.data.proposal.ProposalTermsBlock; +import com.demcha.compose.document.templates.data.proposal.ProposalTitleLines; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalData; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec; + +import java.util.List; + +/** + * Shared sample data for the Editorial proposal example. + * + *

Kept in lockstep with the qa module's + * {@code EditorialProposalFixtures} — the two modules cannot share a source + * file, so a content change here belongs there too.

+ * + *

The sample is the preset's reference content: a two-page + * brand-refresh proposal exercising every band — all four glance facts + * (one with the optional note), four goal cells, five scope rows, both + * deliverable columns, the four-phase grid, an investment table with + * ordinary, subtotal and optional rows plus the total band, four terms, + * and the three-field signing card.

+ * + */ +public final class EditorialProposalSampleData { + + private EditorialProposalSampleData() { + } + + public static StructuredProposalDocumentSpec sample() { + return StructuredProposalDocumentSpec.from(StructuredProposalData.builder() + .brand(new ProposalBrand("N", "NORTHLINE", "STUDIO", "PROPOSAL", + "northlinestudio.com", "NORTHLINE STUDIO")) + .title(new ProposalTitleLines("Proposal —", "Brand Refresh &", + "Website Redesign")) + .meta(new ProposalMetaLine("PREPARED FOR ASTERA HEALTH CO.", + "PREPARED BY NORTHLINE STUDIO", "25 AUGUST 2026")) + .executiveSummary(new ProposalSummaryBlock("Executive Summary", "", List.of( + "Thank you for the opportunity to partner with Astera Health Co. " + + "on your next chapter. This proposal outlines our approach to " + + "refreshing your brand identity and redesigning your website to " + + "better reflect your mission, elevate credibility, and deliver a " + + "seamless experience for the people you serve.", + "Our process blends strategic thinking with thoughtful design to " + + "create a cohesive brand system and a modern, conversion-focused " + + "website. The outcome will be a clear, confident presence that " + + "strengthens trust, improves engagement, and supports your " + + "growth goals."))) + .glance(new ProposalGlance("", List.of( + new ProposalGlance.Fact("fact-duration", "PROJECT DURATION", + "6 weeks", null), + new ProposalGlance.Fact("fact-start", "START WINDOW", + "September 2026", null), + new ProposalGlance.Fact("fact-contact", "PRIMARY CONTACT", + "Project Lead", null), + new ProposalGlance.Fact("fact-validity", "PROPOSAL VALIDITY", + "14 days", "(until 8 September 2026)")))) + .goals(new ProposalGoals("Project Goals", "goal-check", List.of( + new ProposalGoals.Goal("", + "Strengthen brand credibility and visual consistency."), + new ProposalGoals.Goal("", + "Improve website usability and drive meaningful action."), + new ProposalGoals.Goal("", + "Communicate your value clearly across all touchpoints."), + new ProposalGoals.Goal("", + "Build a scalable digital foundation for future growth.")))) + .scope(new ProposalScope("Scope of Work", "", List.of( + new ProposalScope.Item("01", "Discovery & Research", + "Stakeholder interviews, brand audit, competitor review, and " + + "audience insights to inform strategy."), + new ProposalScope.Item("02", "Visual Identity Refinement", + "Refine logo system, color palette, typography, and visual " + + "guidelines for a cohesive, modern identity."), + new ProposalScope.Item("03", "Website UX/UI Design", + "Design a responsive, accessibility-minded website with " + + "intuitive navigation and clear conversion pathways."), + new ProposalScope.Item("04", "Content Structure & Messaging", + "Define site architecture, key messaging, and content " + + "hierarchy to communicate value and build trust."), + new ProposalScope.Item("05", "Launch Support", + "Developer handoff, QA support, training, and go-live " + + "assistance to ensure a smooth launch.")))) + .deliverables(new ProposalDeliverables("Deliverables", "", + List.of("Brand strategy summary", + "Refined logo suite & brand guidelines", + "Color, typography & design system", + "Website UX wireframes", + "High-fidelity website designs"), + List.of("Responsive design for desktop, tablet & mobile", + "Content strategy & page templates", + "Developer-ready assets & specifications", + "Launch checklist & training session"))) + .timeline(new ProposalPhaseGrid("Timeline", "", + List.of("PHASE", "FOCUS", "DURATION", "OUTPUT"), List.of( + new ProposalPhaseGrid.Phase("01", "Discover", + "Research, audit, insights, and strategy", "1 week", + "Discovery report & creative direction"), + new ProposalPhaseGrid.Phase("02", "Design", + "Brand refinement and website UX/UI design", "2 weeks", + "Design system & high-fidelity designs"), + new ProposalPhaseGrid.Phase("03", "Develop Prep", + "Content structure, developer handoff & asset preparation", + "1 week", "Specs, assets & content framework"), + new ProposalPhaseGrid.Phase("04", "Launch Support", + "QA, training & go-live assistance", "2 weeks", + "QA sign-off & successful launch")))) + .investment(new ProposalInvestment("Investment", "", + "ITEM", "AMOUNT (GBP)", List.of( + new ProposalInvestment.Row("Discovery & Strategy", "£2,500", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Brand Identity Refinement", "£4,500", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Website UX/UI Design", "£7,000", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Content Structure & Messaging", "£2,000", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Launch Support", "£1,500", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Subtotal", "£17,500", + ProposalInvestment.Role.SUBTOTAL), + new ProposalInvestment.Row("Optional: 3 Months Post-Launch Support", + "£1,750", ProposalInvestment.Role.OPTIONAL)), + "TOTAL INVESTMENT", "£19,250")) + .terms(new ProposalTermsBlock("Terms", "", List.of( + "50% deposit is required to secure the project and schedule the " + + "kick-off.", + "Includes two rounds of revisions per major deliverable.", + "Final files and handoff delivered upon final payment.", + "Ownership of all final deliverables transfers to Astera Health Co. " + + "after full payment is received."))) + .acceptance(new ProposalAcceptance("Acceptance", "", + "By signing below, you agree to the scope, timeline, investment, " + + "and terms outlined in this proposal.", + List.of("Accepted by:", "Signature:", "Date:"))) + .build()); + } +} diff --git a/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java b/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java index 4af47d427..d12d6b205 100644 --- a/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java +++ b/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java @@ -95,6 +95,7 @@ record Entry(String title, String description, List tags, String codeUrl proposal("proposal-cinematic", "ProposalCinematicFileExample", "Cinematic Proposal", "Layered ModernProposal layout with cover panel, hero spread, and rich typography.", "proposal", "cinematic"); proposal("project-proposal-cinematic", "CinematicProposalFileExample", "Project Proposal (cinematic)", "End-to-end project proposal with mountain hero, scope panels, and pricing summary.", "proposal", "cinematic"); proposal("proposal-modern-v2", "v2/ModernProposalV2Example", "Modern Proposal", "The ModernProposal preset composed straight from its document spec — cover, scope sections and pricing table themed through BrandTheme.", "proposal"); + proposal("proposal-editorial-v2", "v2/EditorialProposalV2Example", "Editorial Proposal", "The EditorialProposal preset — the same structured proposal document as Northline, set in a serif display face with an orange accent, a drawn brand mark and headings over accent rules.", "proposal"); proposal("proposal-northline-v2", "v2/NorthlineProposalV2Example", "Northline Proposal", "The NorthlineProposal preset on the structured proposal model — brand header, stacked title, glance card, goal cells, numbered scope, phase grid, investment table and signing card across two pages.", "proposal"); // ===== Templates / Schedule ===== diff --git a/examples/src/main/java/com/demcha/examples/templates/proposal/v2/EditorialProposalV2Example.java b/examples/src/main/java/com/demcha/examples/templates/proposal/v2/EditorialProposalV2Example.java new file mode 100644 index 000000000..ae4d35bec --- /dev/null +++ b/examples/src/main/java/com/demcha/examples/templates/proposal/v2/EditorialProposalV2Example.java @@ -0,0 +1,53 @@ +package com.demcha.examples.templates.proposal; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.templates.api.DocumentTemplate; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec; +import com.demcha.compose.document.templates.proposal.presets.EditorialProposal; +import com.demcha.examples.support.EditorialProposalSampleData; +import com.demcha.examples.support.ExampleOutputPaths; + +import java.nio.file.Path; + +/** + * Renders the layered {@code proposal.v2} Editorial Proposal preset against + * the structured proposal sample data. + * + *

Output: + * {@code examples/target/generated-pdfs/templates/proposal/proposal-editorial-v2.pdf}.

+ * + *

The same document shape the Northline example renders, in the serif + * editorial look: the preset owns its page geometry, so the session starts + * unconfigured.

+ */ +public final class EditorialProposalV2Example { + + private EditorialProposalV2Example() { + } + + /** + * @return absolute path of the rendered PDF + * @throws Exception if rendering fails + */ + public static Path generate() throws Exception { + Path outputFile = ExampleOutputPaths.prepare( + "templates/proposal", "proposal-editorial-v2.pdf"); + StructuredProposalDocumentSpec spec = EditorialProposalSampleData.sample(); + DocumentTemplate template = EditorialProposal.create(); + + try (DocumentSession document = GraphCompose.document(outputFile).create()) { + template.compose(document, spec); + document.buildPdf(); + } + return outputFile; + } + + /** + * @param args ignored + * @throws Exception if rendering fails + */ + public static void main(String[] args) throws Exception { + System.out.println("Generated: " + generate()); + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalFixtures.java b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalFixtures.java new file mode 100644 index 000000000..ecc8e686a --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalFixtures.java @@ -0,0 +1,148 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.document.templates.data.proposal.ProposalAcceptance; +import com.demcha.compose.document.templates.data.proposal.ProposalBrand; +import com.demcha.compose.document.templates.data.proposal.ProposalDeliverables; +import com.demcha.compose.document.templates.data.proposal.ProposalGlance; +import com.demcha.compose.document.templates.data.proposal.ProposalGoals; +import com.demcha.compose.document.templates.data.proposal.ProposalInvestment; +import com.demcha.compose.document.templates.data.proposal.ProposalMetaLine; +import com.demcha.compose.document.templates.data.proposal.ProposalPhaseGrid; +import com.demcha.compose.document.templates.data.proposal.ProposalScope; +import com.demcha.compose.document.templates.data.proposal.ProposalSummaryBlock; +import com.demcha.compose.document.templates.data.proposal.ProposalTermsBlock; +import com.demcha.compose.document.templates.data.proposal.ProposalTitleLines; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalData; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec; + +import java.util.List; + +/** + * Shared fixture data for the Editorial proposal gates — the SAME spec + * feeds the smoke, layout-snapshot, and pixel gates, so a geometry shift + * the pixel budget absorbs still trips the exact snapshot, and vice versa. + * + *

The canonical fixture is the preset's reference content: a two-page + * brand-refresh proposal exercising every band — all four glance facts + * (one with the optional note), four goal cells, five scope rows, both + * deliverable columns, the four-phase grid, an investment table with + * ordinary, subtotal and optional rows plus the total band, four terms, + * and the three-field signing card.

+ * + *

Kept in lockstep with the examples module's + * {@code EditorialProposalSampleData} — the two modules cannot share a + * source file, so a content change here belongs there too.

+ */ +final class EditorialProposalFixtures { + + private EditorialProposalFixtures() { + } + + static StructuredProposalDocumentSpec canonicalProposal() { + return StructuredProposalDocumentSpec.from(StructuredProposalData.builder() + .brand(new ProposalBrand("N", "NORTHLINE", "STUDIO", "PROPOSAL", + "northlinestudio.com", "NORTHLINE STUDIO")) + .title(new ProposalTitleLines("Proposal —", "Brand Refresh &", + "Website Redesign")) + .meta(new ProposalMetaLine("PREPARED FOR ASTERA HEALTH CO.", + "PREPARED BY NORTHLINE STUDIO", "25 AUGUST 2026")) + .executiveSummary(new ProposalSummaryBlock("Executive Summary", "", List.of( + "Thank you for the opportunity to partner with Astera Health Co. " + + "on your next chapter. This proposal outlines our approach to " + + "refreshing your brand identity and redesigning your website to " + + "better reflect your mission, elevate credibility, and deliver a " + + "seamless experience for the people you serve.", + "Our process blends strategic thinking with thoughtful design to " + + "create a cohesive brand system and a modern, conversion-focused " + + "website. The outcome will be a clear, confident presence that " + + "strengthens trust, improves engagement, and supports your " + + "growth goals."))) + .glance(new ProposalGlance("", List.of( + new ProposalGlance.Fact("fact-duration", "PROJECT DURATION", + "6 weeks", null), + new ProposalGlance.Fact("fact-start", "START WINDOW", + "September 2026", null), + new ProposalGlance.Fact("fact-contact", "PRIMARY CONTACT", + "Project Lead", null), + new ProposalGlance.Fact("fact-validity", "PROPOSAL VALIDITY", + "14 days", "(until 8 September 2026)")))) + .goals(new ProposalGoals("Project Goals", "goal-check", List.of( + new ProposalGoals.Goal("", + "Strengthen brand credibility and visual consistency."), + new ProposalGoals.Goal("", + "Improve website usability and drive meaningful action."), + new ProposalGoals.Goal("", + "Communicate your value clearly across all touchpoints."), + new ProposalGoals.Goal("", + "Build a scalable digital foundation for future growth.")))) + .scope(new ProposalScope("Scope of Work", "", List.of( + new ProposalScope.Item("01", "Discovery & Research", + "Stakeholder interviews, brand audit, competitor review, and " + + "audience insights to inform strategy."), + new ProposalScope.Item("02", "Visual Identity Refinement", + "Refine logo system, color palette, typography, and visual " + + "guidelines for a cohesive, modern identity."), + new ProposalScope.Item("03", "Website UX/UI Design", + "Design a responsive, accessibility-minded website with " + + "intuitive navigation and clear conversion pathways."), + new ProposalScope.Item("04", "Content Structure & Messaging", + "Define site architecture, key messaging, and content " + + "hierarchy to communicate value and build trust."), + new ProposalScope.Item("05", "Launch Support", + "Developer handoff, QA support, training, and go-live " + + "assistance to ensure a smooth launch.")))) + .deliverables(new ProposalDeliverables("Deliverables", "", + List.of("Brand strategy summary", + "Refined logo suite & brand guidelines", + "Color, typography & design system", + "Website UX wireframes", + "High-fidelity website designs"), + List.of("Responsive design for desktop, tablet & mobile", + "Content strategy & page templates", + "Developer-ready assets & specifications", + "Launch checklist & training session"))) + .timeline(new ProposalPhaseGrid("Timeline", "", + List.of("PHASE", "FOCUS", "DURATION", "OUTPUT"), List.of( + new ProposalPhaseGrid.Phase("01", "Discover", + "Research, audit, insights, and strategy", "1 week", + "Discovery report & creative direction"), + new ProposalPhaseGrid.Phase("02", "Design", + "Brand refinement and website UX/UI design", "2 weeks", + "Design system & high-fidelity designs"), + new ProposalPhaseGrid.Phase("03", "Develop Prep", + "Content structure, developer handoff & asset preparation", + "1 week", "Specs, assets & content framework"), + new ProposalPhaseGrid.Phase("04", "Launch Support", + "QA, training & go-live assistance", "2 weeks", + "QA sign-off & successful launch")))) + .investment(new ProposalInvestment("Investment", "", + "ITEM", "AMOUNT (GBP)", List.of( + new ProposalInvestment.Row("Discovery & Strategy", "£2,500", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Brand Identity Refinement", "£4,500", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Website UX/UI Design", "£7,000", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Content Structure & Messaging", "£2,000", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Launch Support", "£1,500", + ProposalInvestment.Role.NONE), + new ProposalInvestment.Row("Subtotal", "£17,500", + ProposalInvestment.Role.SUBTOTAL), + new ProposalInvestment.Row("Optional: 3 Months Post-Launch Support", + "£1,750", ProposalInvestment.Role.OPTIONAL)), + "TOTAL INVESTMENT", "£19,250")) + .terms(new ProposalTermsBlock("Terms", "", List.of( + "50% deposit is required to secure the project and schedule the " + + "kick-off.", + "Includes two rounds of revisions per major deliverable.", + "Final files and handoff delivered upon final payment.", + "Ownership of all final deliverables transfers to Astera Health Co. " + + "after full payment is received."))) + .acceptance(new ProposalAcceptance("Acceptance", "", + "By signing below, you agree to the scope, timeline, investment, " + + "and terms outlined in this proposal.", + List.of("Accepted by:", "Signature:", "Date:"))) + .build()); + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalLayoutSnapshotTest.java b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalLayoutSnapshotTest.java new file mode 100644 index 000000000..b9956ab81 --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalLayoutSnapshotTest.java @@ -0,0 +1,30 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.templates.TemplateTestSupport; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Exact layout snapshot gate for {@link EditorialProposal} — freezes the + * resolved geometry of both pages, including the natural page-one → page-two + * break the masthead's {@code keepWithNext} guarantees. + * + *

Refresh with {@code -Dgraphcompose.updateSnapshots=true} after a + * deliberate layout change, and commit the JSON with the change.

+ */ +class EditorialProposalLayoutSnapshotTest { + + @Test + void canonicalProposalMatchesLayoutSnapshot() throws Exception { + try (DocumentSession session = GraphCompose.document().create()) { + EditorialProposal.create().compose( + session, EditorialProposalFixtures.canonicalProposal()); + assertThat(session.layoutSnapshot().totalPages()).isEqualTo(2); + TemplateTestSupport.assertCanonicalSnapshot( + session, "editorial_proposal_layout", "proposal"); + } + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalSmokeTest.java b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalSmokeTest.java new file mode 100644 index 000000000..8ff267bf7 --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalSmokeTest.java @@ -0,0 +1,172 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.templates.api.DocumentTemplate; +import com.demcha.compose.document.templates.data.proposal.ProposalAcceptance; +import com.demcha.compose.document.templates.data.proposal.ProposalDeliverables; +import com.demcha.compose.document.templates.data.proposal.ProposalInvestment; +import com.demcha.compose.document.templates.data.proposal.ProposalGoals; +import com.demcha.compose.document.templates.data.proposal.ProposalPhaseGrid; +import com.demcha.compose.document.templates.data.proposal.ProposalScope; +import com.demcha.compose.document.templates.data.proposal.ProposalSummaryBlock; +import com.demcha.compose.document.templates.data.proposal.ProposalTermsBlock; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalData; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec; +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.text.PDFTextStripper; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * Smoke test for {@link EditorialProposal} — proves the preset renders a + * {@link StructuredProposalDocumentSpec} end-to-end with its packaged SVG + * icon set, renders an empty document through its guards, puts the table + * content on the text layer where the layout snapshot cannot see it, and + * reports its two data contracts (unknown icon token, phase-grid header + * count) by name. + * + *

It also pins what the two proposal presets do and do not share: the + * document model and the four {@code fact-*} tokens, yes; the badge and + * goal tokens, no — each preset packages its own set.

+ */ +class EditorialProposalSmokeTest { + + private static byte[] render(StructuredProposalDocumentSpec spec) throws Exception { + // The preset owns its page geometry, so the session starts unconfigured. + try (DocumentSession session = GraphCompose.document().create()) { + EditorialProposal.create().compose(session, spec); + assertThat(session.roots()).isNotEmpty(); + byte[] pdfBytes = session.toPdfBytes(); + assertThat(pdfBytes).isNotEmpty(); + return pdfBytes; + } + } + + private static String textOf(byte[] pdfBytes) throws Exception { + try (PDDocument document = Loader.loadPDF(pdfBytes)) { + return new PDFTextStripper().getText(document); + } + } + + @Test + void exposesStableIdentity() { + DocumentTemplate template = EditorialProposal.create(); + assertThat(template.id()).isEqualTo(EditorialProposal.ID); + assertThat(template.displayName()).isEqualTo(EditorialProposal.DISPLAY_NAME); + } + + @Test + void rendersCanonicalProposalWithPackagedIcons() throws Exception { + render(EditorialProposalFixtures.canonicalProposal()); + } + + @Test + void rendersEmptyProposal() throws Exception { + // Exercises the guards: no goal cells, no phase grid, no signature + // row — and the blank icon tokens that carry no packaged mark. + render(StructuredProposalDocumentSpec.from(StructuredProposalData.builder().build())); + } + + @Test + void canonicalRenderCarriesTheTableText() throws Exception { + // The phase grid and the investment table are single leaf nodes in + // the layout snapshot, so their content is asserted on the text layer. + String text = textOf(render(EditorialProposalFixtures.canonicalProposal())); + assertThat(text) + .contains("Discovery report") + .contains("Brand Identity Refinement") + .contains("2 weeks") + .contains("TOTAL INVESTMENT") + .contains("£19,250"); + } + + @Test + void theSameDocumentRendersThroughBothProposalPresets() throws Exception { + // The point of the structured model: one document, two looks. The + // fact tokens are named alike in both packaged sets, so they stay in + // the document; the badge and goal tokens are not, so those are the + // ones a move has to clear. + StructuredProposalDocumentSpec spec = + StructuredProposalDocumentSpec.from(withoutSectionIconTokens( + EditorialProposalFixtures.canonicalProposal().proposal())); + String editorial = textOf(render(spec)); + byte[] northline; + try (DocumentSession session = GraphCompose.document().create()) { + NorthlineProposal.create().compose(session, spec); + northline = session.toPdfBytes(); + } + assertThat(textOf(northline)) + .contains("Executive Summary") + .contains("TOTAL INVESTMENT"); + assertThat(editorial).contains("Executive Summary"); + } + + /** + * The same document with the preset-scoped tokens cleared — every + * section badge and the goal mark — and the shared {@code fact-*} tokens + * left in place, since both packaged sets name those alike. + */ + private static StructuredProposalData withoutSectionIconTokens( + StructuredProposalData data) { + return StructuredProposalData.builder() + .brand(data.brand()) + .title(data.title()) + .meta(data.meta()) + .executiveSummary(new ProposalSummaryBlock(data.executiveSummary().heading(), + "", data.executiveSummary().paragraphs())) + .glance(data.glance()) + .goals(new ProposalGoals(data.goals().heading(), "", + data.goals().items().stream() + .map(g -> new ProposalGoals.Goal("", g.text())) + .toList())) + .scope(new ProposalScope(data.scope().heading(), "", data.scope().items())) + .deliverables(new ProposalDeliverables(data.deliverables().heading(), "", + data.deliverables().leftColumn(), data.deliverables().rightColumn())) + .timeline(new ProposalPhaseGrid(data.timeline().heading(), "", + data.timeline().columnHeaders(), data.timeline().phases())) + .investment(new ProposalInvestment(data.investment().heading(), "", + data.investment().itemHeader(), data.investment().amountHeader(), + data.investment().rows(), data.investment().totalLabel(), + data.investment().totalAmount())) + .terms(new ProposalTermsBlock(data.terms().heading(), "", data.terms().items())) + .acceptance(new ProposalAcceptance(data.acceptance().heading(), "", + data.acceptance().statement(), data.acceptance().fields())) + .build(); + } + + @Test + void rejectsUnknownIconTokenByName() { + StructuredProposalDocumentSpec spec = StructuredProposalDocumentSpec.from( + StructuredProposalData.builder() + .goals(new ProposalGoals("Project Goals", "no-such-icon", + List.of(new ProposalGoals.Goal("", "A goal.")))) + .build()); + try (DocumentSession session = GraphCompose.document().create()) { + assertThatThrownBy(() -> EditorialProposal.create().compose(session, spec)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("no-such-icon"); + } + } + + @Test + void phaseGridRejectsHeaderCountMismatchByName() { + StructuredProposalDocumentSpec spec = StructuredProposalDocumentSpec.from( + StructuredProposalData.builder() + .timeline(new ProposalPhaseGrid("Timeline", "", + List.of("PHASE", "FOCUS", "DURATION"), + List.of(new ProposalPhaseGrid.Phase("01", "Discover", + "Research", "1 week", "Report")))) + .build()); + try (DocumentSession session = GraphCompose.document().create()) { + assertThatThrownBy(() -> EditorialProposal.create().compose(session, spec)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("one header per column"); + } + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalVisualParityTest.java b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalVisualParityTest.java new file mode 100644 index 000000000..f3033ff56 --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposalVisualParityTest.java @@ -0,0 +1,42 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.testing.visual.PdfVisualRegression; +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; + +/** + * Pixel-diff visual parity gate for {@link EditorialProposal} — both pages + * of the canonical fixture against checked-in baselines. + * + *

Re-blessing baselines — after a deliberate visual + * change, re-run with {@code -Dgraphcompose.visual.approve=true} and commit + * the updated PNGs with the change. Baselines live under + * {@code src/test/resources/visual-baselines/proposal-v2-layered/}.

+ */ +class EditorialProposalVisualParityTest { + + private static final Path BASELINE_ROOT = Path.of( + "src", "test", "resources", "visual-baselines", "proposal-v2-layered"); + + private static final long PIXEL_DIFF_BUDGET = 50_000L; + private static final int PER_PIXEL_TOLERANCE = 8; + + @Test + void rendersWithinPixelDiffBudget() throws Exception { + byte[] pdfBytes; + try (DocumentSession document = GraphCompose.document().create()) { + EditorialProposal.create().compose( + document, EditorialProposalFixtures.canonicalProposal()); + pdfBytes = document.toPdfBytes(); + } + + PdfVisualRegression.standard() + .baselineRoot(BASELINE_ROOT) + .perPixelTolerance(PER_PIXEL_TOLERANCE) + .mismatchedPixelBudget(PIXEL_DIFF_BUDGET) + .assertMatchesBaseline("editorial_proposal", pdfBytes); + } +} diff --git a/qa/src/test/resources/layout-snapshots/canonical-templates/proposal/editorial_proposal_layout.json b/qa/src/test/resources/layout-snapshots/canonical-templates/proposal/editorial_proposal_layout.json new file mode 100644 index 000000000..59abca9ef --- /dev/null +++ b/qa/src/test/resources/layout-snapshots/canonical-templates/proposal/editorial_proposal_layout.json @@ -0,0 +1,5567 @@ +{ + "formatVersion" : "2.0", + "canvas" : { + "pageWidth" : 595.276, + "pageHeight" : 841.89, + "innerWidth" : 535.276, + "innerHeight" : 773.19, + "margin" : { + "top" : 19.7, + "right" : 30.0, + "bottom" : 49.0, + "left" : 30.0 + } + }, + "totalPages" : 2, + "nodes" : [ { + "path" : "Proposal[0]", + "entityName" : "Proposal", + "entityKind" : "ContainerNode", + "parentPath" : null, + "childIndex" : 0, + "depth" : 1, + "layer" : 1, + "computedX" : 30.0, + "computedY" : -673.275, + "placementX" : 30.0, + "placementY" : -673.275, + "placementWidth" : 535.276, + "placementHeight" : 1495.465, + "startPage" : 0, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 1495.465, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]", + "entityName" : "Masthead", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 0, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 775.788, + "placementX" : 30.0, + "placementY" : 775.788, + "placementWidth" : 535.276, + "placementHeight" : 46.402, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 46.402, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]", + "entityName" : "MastheadRow", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/Masthead[0]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 792.888, + "placementX" : 30.0, + "placementY" : 792.888, + "placementWidth" : 535.276, + "placementHeight" : 29.302, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 29.302, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]", + "entityName" : "LogoMark", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]/MarkStem[0]", + "entityName" : "MarkStem", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]/MarkDiagonal[1]", + "entityName" : "MarkDiagonal", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]/MarkSlash[2]", + "entityName" : "MarkSlash", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]/MarkRightStem[3]", + "entityName" : "MarkRightStem", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/Wordmark[1]", + "entityName" : "Wordmark", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 69.0, + "computedY" : 792.888, + "placementX" : 69.0, + "placementY" : 792.888, + "placementWidth" : 101.702, + "placementHeight" : 29.302, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 101.702, + "contentHeight" : 29.302, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/Wordmark[1]/WordmarkLine1[0]", + "entityName" : "WordmarkLine1", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/Wordmark[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 69.0, + "computedY" : 802.87, + "placementX" : 69.0, + "placementY" : 802.87, + "placementWidth" : 92.672, + "placementHeight" : 19.32, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 92.672, + "contentHeight" : 19.32, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/Wordmark[1]/WordmarkLine2[1]", + "entityName" : "WordmarkLine2", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/Wordmark[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 69.0, + "computedY" : 792.188, + "placementX" : 69.0, + "placementY" : 792.188, + "placementWidth" : 52.612, + "placementHeight" : 16.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 52.612, + "contentHeight" : 16.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/SpacerNode[2]", + "entityName" : null, + "entityKind" : "SpacerNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 179.702, + "computedY" : 807.539, + "placementX" : 179.702, + "placementY" : 807.539, + "placementWidth" : 0.0, + "placementHeight" : 0.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 0.0, + "contentHeight" : 0.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/DocumentLabel[3]", + "entityName" : "DocumentLabel", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 495.69, + "computedY" : 799.259, + "placementX" : 495.69, + "placementY" : 799.259, + "placementWidth" : 69.586, + "placementHeight" : 16.56, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 69.586, + "contentHeight" : 16.56, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 8.5, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/DocumentLabel[3]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/DocumentLabel[3]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 495.69, + "computedY" : 805.859, + "placementX" : 495.69, + "placementY" : 805.859, + "placementWidth" : 61.086, + "placementHeight" : 9.96, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 61.086, + "contentHeight" : 9.96, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/DocumentLabel[3]/Align[1]", + "entityName" : null, + "entityKind" : "Align", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/DocumentLabel[3]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 495.69, + "computedY" : 799.259, + "placementX" : 495.69, + "placementY" : 799.259, + "placementWidth" : 61.086, + "placementHeight" : 6.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 61.086, + "contentHeight" : 6.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/MastheadRow[0]/DocumentLabel[3]/Align[1]/DocumentLabelRule[0]", + "entityName" : "DocumentLabelRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Masthead[0]/MastheadRow[0]/DocumentLabel[3]/Align[1]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 495.69, + "computedY" : 799.259, + "placementX" : 495.69, + "placementY" : 799.259, + "placementWidth" : 61.557, + "placementHeight" : 1.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 61.557, + "contentHeight" : 1.6, + "margin" : { + "top" : 5.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[0]/LineNode[1]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Masthead[0]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 775.788, + "placementX" : 30.0, + "placementY" : 775.788, + "placementWidth" : 535.276, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 1.0, + "margin" : { + "top" : 16.1, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/TitleBlock[1]", + "entityName" : "TitleBlock", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 1, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 634.688, + "placementX" : 30.0, + "placementY" : 634.688, + "placementWidth" : 535.276, + "placementHeight" : 125.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 125.6, + "margin" : { + "top" : 15.5, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/TitleBlock[1]/TitleLines[0]", + "entityName" : "TitleLines", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/TitleBlock[1]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 634.688, + "placementX" : 30.0, + "placementY" : 634.688, + "placementWidth" : 535.276, + "placementHeight" : 125.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 125.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/TitleBlock[1]/TitleLines[0]/TitleLinesLine1[0]", + "entityName" : "TitleLinesLine1", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/TitleBlock[1]/TitleLines[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 696.668, + "placementX" : 30.0, + "placementY" : 696.668, + "placementWidth" : 222.376, + "placementHeight" : 63.62, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 222.376, + "contentHeight" : 63.62, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/TitleBlock[1]/TitleLines[0]/TitleLinesLine2[1]", + "entityName" : "TitleLinesLine2", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/TitleBlock[1]/TitleLines[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 654.768, + "placementX" : 30.0, + "placementY" : 654.768, + "placementWidth" : 321.108, + "placementHeight" : 63.62, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 321.108, + "contentHeight" : 63.62, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/TitleBlock[1]/TitleLines[0]/TitleLinesLine3[2]", + "entityName" : "TitleLinesLine3", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/TitleBlock[1]/TitleLines[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 612.868, + "placementX" : 30.0, + "placementY" : 612.868, + "placementWidth" : 344.975, + "placementHeight" : 63.62, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 344.975, + "contentHeight" : 63.62, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/TitleMeta[2]", + "entityName" : "TitleMeta", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 2, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 606.088, + "placementX" : 30.0, + "placementY" : 606.088, + "placementWidth" : 476.889, + "placementHeight" : 12.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 476.889, + "contentHeight" : 12.6, + "margin" : { + "top" : 16.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/TitleMeta[2]/MetaLine[0]", + "entityName" : "MetaLine", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/TitleMeta[2]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 606.088, + "placementX" : 30.0, + "placementY" : 606.088, + "placementWidth" : 476.889, + "placementHeight" : 12.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 476.889, + "contentHeight" : 12.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]", + "entityName" : "SummaryBand", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]", + "childIndex" : 3, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 359.121, + "placementX" : 30.0, + "placementY" : 359.121, + "placementWidth" : 535.276, + "placementHeight" : 229.167, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 229.167, + "margin" : { + "top" : 17.8, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]", + "entityName" : "SummaryColumn", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 359.121, + "placementX" : 30.0, + "placementY" : 359.121, + "placementWidth" : 318.63, + "placementHeight" : 229.167, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 318.63, + "contentHeight" : 229.167, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[0]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 560.879, + "placementX" : 30.0, + "placementY" : 560.879, + "placementWidth" : 148.672, + "placementHeight" : 27.409, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 148.672, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[0]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 563.479, + "placementX" : 30.0, + "placementY" : 563.479, + "placementWidth" : 148.672, + "placementHeight" : 24.809, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 148.672, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[0]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 560.879, + "placementX" : 30.0, + "placementY" : 560.879, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 479.179, + "placementX" : 30.0, + "placementY" : 479.179, + "placementWidth" : 318.63, + "placementHeight" : 72.2, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 318.63, + "contentHeight" : 72.2, + "margin" : { + "top" : 9.5, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 413.029, + "placementX" : 30.0, + "placementY" : 413.029, + "placementWidth" : 314.24, + "placementHeight" : 57.15, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 314.24, + "contentHeight" : 57.15, + "margin" : { + "top" : 9.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SpacerNode[3]", + "entityName" : null, + "entityKind" : "SpacerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 386.529, + "placementX" : 30.0, + "placementY" : 386.529, + "placementWidth" : 0.0, + "placementHeight" : 26.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 0.0, + "contentHeight" : 26.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[4]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]", + "childIndex" : 4, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 359.121, + "placementX" : 30.0, + "placementY" : 359.121, + "placementWidth" : 100.783, + "placementHeight" : 27.409, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 100.783, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[4]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[4]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 361.721, + "placementX" : 30.0, + "placementY" : 361.721, + "placementWidth" : 100.783, + "placementHeight" : 24.809, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 100.783, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[4]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/SummaryColumn[0]/SectionHeading[4]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 359.121, + "placementX" : 30.0, + "placementY" : 359.121, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]", + "entityName" : "GlanceColumn", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 384.353, + "computedY" : 361.97, + "placementX" : 384.353, + "placementY" : 361.97, + "placementWidth" : 180.923, + "placementHeight" : 226.318, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 180.923, + "contentHeight" : 226.318, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 5.246, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "entityName" : "GlancePanel", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 384.353, + "computedY" : 361.97, + "placementX" : 384.353, + "placementY" : 361.97, + "placementWidth" : 180.923, + "placementHeight" : 221.072, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 180.923, + "contentHeight" : 221.072, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 17.0, + "right" : 17.0, + "bottom" : 17.0, + "left" : 17.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]", + "entityName" : "GlanceFact", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 401.353, + "computedY" : 533.863, + "placementX" : 401.353, + "placementY" : 533.863, + "placementWidth" : 146.923, + "placementHeight" : 32.18, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 146.923, + "contentHeight" : 32.18, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/Icon-fact-duration[0]", + "entityName" : "Icon-fact-duration", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 401.353, + "computedY" : 539.952, + "placementX" : 401.353, + "placementY" : 539.952, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/Icon-fact-duration[0]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/Icon-fact-duration[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 401.353, + "computedY" : 539.952, + "placementX" : 401.353, + "placementY" : 539.952, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/Icon-fact-duration[0]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/Icon-fact-duration[0]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 8, + "layer" : 8, + "computedX" : 401.353, + "computedY" : 539.952, + "placementX" : 401.353, + "placementY" : 539.952, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/FactText[1]", + "entityName" : "FactText", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 435.353, + "computedY" : 537.052, + "placementX" : 435.353, + "placementY" : 537.052, + "placementWidth" : 74.235, + "placementHeight" : 25.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 74.235, + "contentHeight" : 25.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/FactText[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/FactText[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 553.852, + "placementX" : 435.353, + "placementY" : 553.852, + "placementWidth" : 74.235, + "placementHeight" : 9.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 74.235, + "contentHeight" : 9.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/FactText[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[0]/FactText[1]", + "childIndex" : 1, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 537.052, + "placementX" : 435.353, + "placementY" : 537.052, + "placementWidth" : 51.366, + "placementHeight" : 16.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 51.366, + "contentHeight" : 16.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/LineNode[1]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 401.353, + "computedY" : 525.763, + "placementX" : 401.353, + "placementY" : 525.763, + "placementWidth" : 146.923, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 146.923, + "contentHeight" : 1.0, + "margin" : { + "top" : 7.1, + "right" : 0.0, + "bottom" : 7.1, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]", + "entityName" : "GlanceFact", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 401.353, + "computedY" : 486.483, + "placementX" : 401.353, + "placementY" : 486.483, + "placementWidth" : 146.923, + "placementHeight" : 32.18, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 146.923, + "contentHeight" : 32.18, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/Icon-fact-start[0]", + "entityName" : "Icon-fact-start", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 401.353, + "computedY" : 492.573, + "placementX" : 401.353, + "placementY" : 492.573, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/Icon-fact-start[0]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/Icon-fact-start[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 401.353, + "computedY" : 492.573, + "placementX" : 401.353, + "placementY" : 492.573, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/Icon-fact-start[0]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/Icon-fact-start[0]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 8, + "layer" : 8, + "computedX" : 401.353, + "computedY" : 492.573, + "placementX" : 401.353, + "placementY" : 492.573, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/FactText[1]", + "entityName" : "FactText", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 435.353, + "computedY" : 489.673, + "placementX" : 435.353, + "placementY" : 489.673, + "placementWidth" : 104.062, + "placementHeight" : 25.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 104.062, + "contentHeight" : 25.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/FactText[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/FactText[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 506.473, + "placementX" : 435.353, + "placementY" : 506.473, + "placementWidth" : 60.518, + "placementHeight" : 9.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 60.518, + "contentHeight" : 9.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/FactText[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[2]/FactText[1]", + "childIndex" : 1, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 489.673, + "placementX" : 435.353, + "placementY" : 489.673, + "placementWidth" : 104.062, + "placementHeight" : 16.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 104.062, + "contentHeight" : 16.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/LineNode[3]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 401.353, + "computedY" : 478.383, + "placementX" : 401.353, + "placementY" : 478.383, + "placementWidth" : 146.923, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 146.923, + "contentHeight" : 1.0, + "margin" : { + "top" : 7.1, + "right" : 0.0, + "bottom" : 7.1, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]", + "entityName" : "GlanceFact", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "childIndex" : 4, + "depth" : 5, + "layer" : 5, + "computedX" : 401.353, + "computedY" : 439.104, + "placementX" : 401.353, + "placementY" : 439.104, + "placementWidth" : 146.923, + "placementHeight" : 32.18, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 146.923, + "contentHeight" : 32.18, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/Icon-fact-contact[0]", + "entityName" : "Icon-fact-contact", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 401.353, + "computedY" : 445.193, + "placementX" : 401.353, + "placementY" : 445.193, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/Icon-fact-contact[0]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/Icon-fact-contact[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 401.353, + "computedY" : 445.193, + "placementX" : 401.353, + "placementY" : 445.193, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/Icon-fact-contact[0]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/Icon-fact-contact[0]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 8, + "layer" : 8, + "computedX" : 401.353, + "computedY" : 445.193, + "placementX" : 401.353, + "placementY" : 445.193, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/FactText[1]", + "entityName" : "FactText", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 435.353, + "computedY" : 442.293, + "placementX" : 435.353, + "placementY" : 442.293, + "placementWidth" : 78.148, + "placementHeight" : 25.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 78.148, + "contentHeight" : 25.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/FactText[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/FactText[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 459.093, + "placementX" : 435.353, + "placementY" : 459.093, + "placementWidth" : 71.483, + "placementHeight" : 9.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 71.483, + "contentHeight" : 9.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/FactText[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[4]/FactText[1]", + "childIndex" : 1, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 442.293, + "placementX" : 435.353, + "placementY" : 442.293, + "placementWidth" : 78.148, + "placementHeight" : 16.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 78.148, + "contentHeight" : 16.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/LineNode[5]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "childIndex" : 5, + "depth" : 5, + "layer" : 5, + "computedX" : 401.353, + "computedY" : 431.004, + "placementX" : 401.353, + "placementY" : 431.004, + "placementWidth" : 146.923, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 146.923, + "contentHeight" : 1.0, + "margin" : { + "top" : 7.1, + "right" : 0.0, + "bottom" : 7.1, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]", + "entityName" : "GlanceFact", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]", + "childIndex" : 6, + "depth" : 5, + "layer" : 5, + "computedX" : 401.353, + "computedY" : 378.97, + "placementX" : 401.353, + "placementY" : 378.97, + "placementWidth" : 146.923, + "placementHeight" : 44.934, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 146.923, + "contentHeight" : 44.934, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/Icon-fact-validity[0]", + "entityName" : "Icon-fact-validity", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 401.353, + "computedY" : 391.437, + "placementX" : 401.353, + "placementY" : 391.437, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/Icon-fact-validity[0]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/Icon-fact-validity[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 401.353, + "computedY" : 391.437, + "placementX" : 401.353, + "placementY" : 391.437, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/Icon-fact-validity[0]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/Icon-fact-validity[0]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 8, + "layer" : 8, + "computedX" : 401.353, + "computedY" : 391.437, + "placementX" : 401.353, + "placementY" : 391.437, + "placementWidth" : 20.0, + "placementHeight" : 20.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.0, + "contentHeight" : 20.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/FactText[1]", + "entityName" : "FactText", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 435.353, + "computedY" : 383.737, + "placementX" : 435.353, + "placementY" : 383.737, + "placementWidth" : 87.576, + "placementHeight" : 35.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 87.576, + "contentHeight" : 35.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/FactText[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/FactText[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 410.137, + "placementX" : 435.353, + "placementY" : 410.137, + "placementWidth" : 75.128, + "placementHeight" : 9.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 75.128, + "contentHeight" : 9.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/FactText[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/FactText[1]", + "childIndex" : 1, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 393.337, + "placementX" : 435.353, + "placementY" : 393.337, + "placementWidth" : 48.258, + "placementHeight" : 16.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 48.258, + "contentHeight" : 16.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/FactText[1]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/SummaryBand[3]/GlanceColumn[1]/GlancePanel[0]/GlanceFact[6]/FactText[1]", + "childIndex" : 2, + "depth" : 7, + "layer" : 7, + "computedX" : 435.353, + "computedY" : 383.737, + "placementX" : 435.353, + "placementY" : 383.737, + "placementWidth" : 87.576, + "placementHeight" : 9.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 87.576, + "contentHeight" : 9.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]", + "entityName" : "GoalCells", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]", + "childIndex" : 4, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 299.42, + "placementX" : 30.0, + "placementY" : 299.42, + "placementWidth" : 535.276, + "placementHeight" : 41.901, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 41.901, + "margin" : { + "top" : 17.8, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[0]", + "entityName" : "Icon-goal-check", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 325.321, + "placementX" : 30.0, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[0]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 325.321, + "placementX" : 30.0, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[0]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[0]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 325.321, + "placementX" : 30.0, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 54.0, + "computedY" : 302.821, + "placementX" : 54.0, + "placementY" : 302.821, + "placementWidth" : 80.352, + "placementHeight" : 38.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 80.352, + "contentHeight" : 38.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/LineNode[2]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 2, + "depth" : 3, + "layer" : 3, + "computedX" : 159.294, + "computedY" : 299.42, + "placementX" : 159.294, + "placementY" : 299.42, + "placementWidth" : 1.0, + "placementHeight" : 41.901, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 41.901, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[3]", + "entityName" : "Icon-goal-check", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 3, + "depth" : 3, + "layer" : 3, + "computedX" : 167.994, + "computedY" : 325.321, + "placementX" : 167.994, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[3]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[3]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 167.994, + "computedY" : 325.321, + "placementX" : 167.994, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[3]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[3]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 167.994, + "computedY" : 325.321, + "placementX" : 167.994, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/ParagraphNode[4]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 4, + "depth" : 3, + "layer" : 3, + "computedX" : 191.994, + "computedY" : 302.821, + "placementX" : 191.994, + "placementY" : 302.821, + "placementWidth" : 72.54, + "placementHeight" : 38.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 72.54, + "contentHeight" : 38.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/LineNode[5]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 5, + "depth" : 3, + "layer" : 3, + "computedX" : 297.288, + "computedY" : 299.42, + "placementX" : 297.288, + "placementY" : 299.42, + "placementWidth" : 1.0, + "placementHeight" : 41.901, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 41.901, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[6]", + "entityName" : "Icon-goal-check", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 6, + "depth" : 3, + "layer" : 3, + "computedX" : 305.988, + "computedY" : 325.321, + "placementX" : 305.988, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[6]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[6]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 305.988, + "computedY" : 325.321, + "placementX" : 305.988, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[6]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[6]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 305.988, + "computedY" : 325.321, + "placementX" : 305.988, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/ParagraphNode[7]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 7, + "depth" : 3, + "layer" : 3, + "computedX" : 329.988, + "computedY" : 302.821, + "placementX" : 329.988, + "placementY" : 302.821, + "placementWidth" : 87.291, + "placementHeight" : 38.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 87.291, + "contentHeight" : 38.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/LineNode[8]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 8, + "depth" : 3, + "layer" : 3, + "computedX" : 435.282, + "computedY" : 299.42, + "placementX" : 435.282, + "placementY" : 299.42, + "placementWidth" : 1.0, + "placementHeight" : 41.901, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 41.901, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[9]", + "entityName" : "Icon-goal-check", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 9, + "depth" : 3, + "layer" : 3, + "computedX" : 443.982, + "computedY" : 325.321, + "placementX" : 443.982, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[9]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[9]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 443.982, + "computedY" : 325.321, + "placementX" : 443.982, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/Icon-goal-check[9]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/GoalCells[4]/Icon-goal-check[9]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 443.982, + "computedY" : 325.321, + "placementX" : 443.982, + "placementY" : 325.321, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/GoalCells[4]/ParagraphNode[10]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/GoalCells[4]", + "childIndex" : 10, + "depth" : 3, + "layer" : 3, + "computedX" : 467.982, + "computedY" : 302.821, + "placementX" : 467.982, + "placementY" : 302.821, + "placementWidth" : 86.607, + "placementHeight" : 38.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 86.607, + "contentHeight" : 38.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]", + "entityName" : "ScopeOfWork", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 5, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 88.911, + "placementX" : 30.0, + "placementY" : 88.911, + "placementWidth" : 535.276, + "placementHeight" : 192.709, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 192.709, + "margin" : { + "top" : 17.8, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/SectionHeading[0]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 254.211, + "placementX" : 30.0, + "placementY" : 254.211, + "placementWidth" : 109.585, + "placementHeight" : 27.409, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 109.585, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/SectionHeading[0]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/SectionHeading[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 256.811, + "placementX" : 30.0, + "placementY" : 256.811, + "placementWidth" : 109.585, + "placementHeight" : 24.809, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 109.585, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/SectionHeading[0]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/SectionHeading[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 254.211, + "placementX" : 30.0, + "placementY" : 254.211, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/LineNode[1]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 243.711, + "placementX" : 30.0, + "placementY" : 243.711, + "placementWidth" : 535.276, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 1.0, + "margin" : { + "top" : 9.5, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow01[2]", + "entityName" : "ScopeRow01", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 2, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 213.551, + "placementX" : 30.0, + "placementY" : 213.551, + "placementWidth" : 535.276, + "placementHeight" : 30.16, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 30.16, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 2.9, + "right" : 0.0, + "bottom" : 2.9, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow01[2]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow01[2]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 230.011, + "placementX" : 30.0, + "placementY" : 230.011, + "placementWidth" : 10.44, + "placementHeight" : 10.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 10.44, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow01[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow01[2]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 64.0, + "computedY" : 229.411, + "placementX" : 64.0, + "placementY" : 229.411, + "placementWidth" : 92.748, + "placementHeight" : 11.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 92.748, + "contentHeight" : 11.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow01[2]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow01[2]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 260.169, + "computedY" : 216.451, + "placementX" : 260.169, + "placementY" : 216.451, + "placementWidth" : 259.311, + "placementHeight" : 24.36, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 259.311, + "contentHeight" : 24.36, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/LineNode[3]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 3, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 212.551, + "placementX" : 30.0, + "placementY" : 212.551, + "placementWidth" : 535.276, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 1.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow02[4]", + "entityName" : "ScopeRow02", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 4, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 182.391, + "placementX" : 30.0, + "placementY" : 182.391, + "placementWidth" : 535.276, + "placementHeight" : 30.16, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 30.16, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 2.9, + "right" : 0.0, + "bottom" : 2.9, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow02[4]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow02[4]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 198.851, + "placementX" : 30.0, + "placementY" : 198.851, + "placementWidth" : 10.44, + "placementHeight" : 10.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 10.44, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow02[4]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow02[4]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 64.0, + "computedY" : 198.251, + "placementX" : 64.0, + "placementY" : 198.251, + "placementWidth" : 112.87, + "placementHeight" : 11.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 112.87, + "contentHeight" : 11.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow02[4]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow02[4]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 260.169, + "computedY" : 185.291, + "placementX" : 260.169, + "placementY" : 185.291, + "placementWidth" : 244.342, + "placementHeight" : 24.36, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 244.342, + "contentHeight" : 24.36, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/LineNode[5]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 5, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 181.391, + "placementX" : 30.0, + "placementY" : 181.391, + "placementWidth" : 535.276, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 1.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow03[6]", + "entityName" : "ScopeRow03", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 6, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 151.231, + "placementX" : 30.0, + "placementY" : 151.231, + "placementWidth" : 535.276, + "placementHeight" : 30.16, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 30.16, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 2.9, + "right" : 0.0, + "bottom" : 2.9, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow03[6]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow03[6]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 167.691, + "placementX" : 30.0, + "placementY" : 167.691, + "placementWidth" : 10.44, + "placementHeight" : 10.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 10.44, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow03[6]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow03[6]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 64.0, + "computedY" : 167.091, + "placementX" : 64.0, + "placementY" : 167.091, + "placementWidth" : 97.28, + "placementHeight" : 11.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 97.28, + "contentHeight" : 11.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow03[6]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow03[6]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 260.169, + "computedY" : 154.131, + "placementX" : 260.169, + "placementY" : 154.131, + "placementWidth" : 276.032, + "placementHeight" : 24.36, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 276.032, + "contentHeight" : 24.36, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/LineNode[7]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 7, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 150.231, + "placementX" : 30.0, + "placementY" : 150.231, + "placementWidth" : 535.276, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 1.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow04[8]", + "entityName" : "ScopeRow04", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 8, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 120.071, + "placementX" : 30.0, + "placementY" : 120.071, + "placementWidth" : 535.276, + "placementHeight" : 30.16, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 30.16, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 2.9, + "right" : 0.0, + "bottom" : 2.9, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow04[8]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow04[8]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 136.531, + "placementX" : 30.0, + "placementY" : 136.531, + "placementWidth" : 10.44, + "placementHeight" : 10.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 10.44, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow04[8]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow04[8]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 64.0, + "computedY" : 135.931, + "placementX" : 64.0, + "placementY" : 135.931, + "placementWidth" : 133.19, + "placementHeight" : 11.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 133.19, + "contentHeight" : 11.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow04[8]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow04[8]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 260.169, + "computedY" : 122.971, + "placementX" : 260.169, + "placementY" : 122.971, + "placementWidth" : 282.091, + "placementHeight" : 24.36, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 282.091, + "contentHeight" : 24.36, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/LineNode[9]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 9, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 119.071, + "placementX" : 30.0, + "placementY" : 119.071, + "placementWidth" : 535.276, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 1.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow05[10]", + "entityName" : "ScopeRow05", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]", + "childIndex" : 10, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 88.911, + "placementX" : 30.0, + "placementY" : 88.911, + "placementWidth" : 535.276, + "placementHeight" : 30.16, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 535.276, + "contentHeight" : 30.16, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 2.9, + "right" : 0.0, + "bottom" : 2.9, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow05[10]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow05[10]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 105.371, + "placementX" : 30.0, + "placementY" : 105.371, + "placementWidth" : 10.44, + "placementHeight" : 10.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 10.44, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow05[10]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow05[10]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 64.0, + "computedY" : 104.771, + "placementX" : 64.0, + "placementY" : 104.771, + "placementWidth" : 66.633, + "placementHeight" : 11.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 66.633, + "contentHeight" : 11.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/ScopeOfWork[5]/ScopeRow05[10]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/ScopeOfWork[5]/ScopeRow05[10]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 260.169, + "computedY" : 91.811, + "placementX" : 260.169, + "placementY" : 91.811, + "placementWidth" : 274.933, + "placementHeight" : 24.36, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 274.933, + "contentHeight" : 24.36, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]", + "entityName" : "Masthead", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 6, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 775.788, + "placementX" : 30.0, + "placementY" : 775.788, + "placementWidth" : 535.276, + "placementHeight" : 46.402, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 46.402, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]", + "entityName" : "MastheadRow", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/Masthead[6]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 792.888, + "placementX" : 30.0, + "placementY" : 792.888, + "placementWidth" : 535.276, + "placementHeight" : 29.302, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 29.302, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]", + "entityName" : "LogoMark", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]/MarkStem[0]", + "entityName" : "MarkStem", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]/MarkDiagonal[1]", + "entityName" : "MarkDiagonal", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]/MarkSlash[2]", + "entityName" : "MarkSlash", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]/MarkRightStem[3]", + "entityName" : "MarkRightStem", + "entityKind" : "Path", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/LogoMark[0]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 794.539, + "placementX" : 30.0, + "placementY" : 794.539, + "placementWidth" : 30.0, + "placementHeight" : 26.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 30.0, + "contentHeight" : 26.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/Wordmark[1]", + "entityName" : "Wordmark", + "entityKind" : "ShapeContainerNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 69.0, + "computedY" : 792.888, + "placementX" : 69.0, + "placementY" : 792.888, + "placementWidth" : 101.702, + "placementHeight" : 29.302, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 101.702, + "contentHeight" : 29.302, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/Wordmark[1]/WordmarkLine1[0]", + "entityName" : "WordmarkLine1", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/Wordmark[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 69.0, + "computedY" : 802.87, + "placementX" : 69.0, + "placementY" : 802.87, + "placementWidth" : 92.672, + "placementHeight" : 19.32, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 92.672, + "contentHeight" : 19.32, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/Wordmark[1]/WordmarkLine2[1]", + "entityName" : "WordmarkLine2", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/Wordmark[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 69.0, + "computedY" : 792.188, + "placementX" : 69.0, + "placementY" : 792.188, + "placementWidth" : 52.612, + "placementHeight" : 16.8, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 52.612, + "contentHeight" : 16.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/SpacerNode[2]", + "entityName" : null, + "entityKind" : "SpacerNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 179.702, + "computedY" : 807.539, + "placementX" : 179.702, + "placementY" : 807.539, + "placementWidth" : 0.0, + "placementHeight" : 0.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 0.0, + "contentHeight" : 0.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/DocumentLabel[3]", + "entityName" : "DocumentLabel", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 495.69, + "computedY" : 799.259, + "placementX" : 495.69, + "placementY" : 799.259, + "placementWidth" : 69.586, + "placementHeight" : 16.56, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 69.586, + "contentHeight" : 16.56, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 8.5, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/DocumentLabel[3]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/DocumentLabel[3]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 495.69, + "computedY" : 805.859, + "placementX" : 495.69, + "placementY" : 805.859, + "placementWidth" : 61.086, + "placementHeight" : 9.96, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 61.086, + "contentHeight" : 9.96, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/DocumentLabel[3]/Align[1]", + "entityName" : null, + "entityKind" : "Align", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/DocumentLabel[3]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 495.69, + "computedY" : 799.259, + "placementX" : 495.69, + "placementY" : 799.259, + "placementWidth" : 61.086, + "placementHeight" : 6.6, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 61.086, + "contentHeight" : 6.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/MastheadRow[0]/DocumentLabel[3]/Align[1]/DocumentLabelRule[0]", + "entityName" : "DocumentLabelRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Masthead[6]/MastheadRow[0]/DocumentLabel[3]/Align[1]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 495.69, + "computedY" : 799.259, + "placementX" : 495.69, + "placementY" : 799.259, + "placementWidth" : 61.557, + "placementHeight" : 1.6, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 61.557, + "contentHeight" : 1.6, + "margin" : { + "top" : 5.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Masthead[6]/LineNode[1]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Masthead[6]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 775.788, + "placementX" : 30.0, + "placementY" : 775.788, + "placementWidth" : 535.276, + "placementHeight" : 1.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 1.0, + "margin" : { + "top" : 16.1, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]", + "entityName" : "Deliverables", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 7, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 629.479, + "placementX" : 30.0, + "placementY" : 629.479, + "placementWidth" : 535.276, + "placementHeight" : 127.309, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 127.309, + "margin" : { + "top" : 19.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/SectionHeading[0]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Deliverables[7]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 729.379, + "placementX" : 30.0, + "placementY" : 729.379, + "placementWidth" : 93.073, + "placementHeight" : 27.409, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 93.073, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/SectionHeading[0]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/SectionHeading[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 731.979, + "placementX" : 30.0, + "placementY" : 731.979, + "placementWidth" : 93.073, + "placementHeight" : 24.809, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 93.073, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/SectionHeading[0]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Deliverables[7]/SectionHeading[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 729.379, + "placementX" : 30.0, + "placementY" : 729.379, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]", + "entityName" : "DeliverableColumns", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/Deliverables[7]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 629.479, + "placementX" : 30.0, + "placementY" : 629.479, + "placementWidth" : 535.276, + "placementHeight" : 99.9, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 99.9, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 9.5, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]", + "entityName" : "DeliverablesLeft", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 629.479, + "placementX" : 30.0, + "placementY" : 629.479, + "placementWidth" : 174.6, + "placementHeight" : 90.4, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 174.6, + "contentHeight" : 90.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 707.879, + "placementX" : 30.0, + "placementY" : 707.879, + "placementWidth" : 118.56, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 118.56, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 688.279, + "placementX" : 30.0, + "placementY" : 688.279, + "placementWidth" : 174.6, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 174.6, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 668.679, + "placementX" : 30.0, + "placementY" : 668.679, + "placementWidth" : 164.43, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 164.43, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]/ParagraphNode[3]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 649.079, + "placementX" : 30.0, + "placementY" : 649.079, + "placementWidth" : 116.23, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 116.23, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]/ParagraphNode[4]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesLeft[0]", + "childIndex" : 4, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 629.479, + "placementX" : 30.0, + "placementY" : 629.479, + "placementWidth" : 138.3, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 138.3, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]", + "entityName" : "DeliverablesRight", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 292.821, + "computedY" : 635.259, + "placementX" : 292.821, + "placementY" : 635.259, + "placementWidth" : 186.8, + "placementHeight" : 84.62, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 186.8, + "contentHeight" : 84.62, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 292.821, + "computedY" : 694.059, + "placementX" : 292.821, + "placementY" : 694.059, + "placementWidth" : 185.14, + "placementHeight" : 25.82, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 185.14, + "contentHeight" : 25.82, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 292.821, + "computedY" : 674.459, + "placementX" : 292.821, + "placementY" : 674.459, + "placementWidth" : 164.67, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 164.67, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 292.821, + "computedY" : 654.859, + "placementX" : 292.821, + "placementY" : 654.859, + "placementWidth" : 186.8, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 186.8, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]/ParagraphNode[3]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Deliverables[7]/DeliverableColumns[1]/DeliverablesRight[1]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 292.821, + "computedY" : 635.259, + "placementX" : 292.821, + "placementY" : 635.259, + "placementWidth" : 163.73, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 163.73, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Timeline[8]", + "entityName" : "Timeline", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 8, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 405.621, + "placementX" : 30.0, + "placementY" : 405.621, + "placementWidth" : 535.276, + "placementHeight" : 206.059, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 206.059, + "margin" : { + "top" : 17.8, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Timeline[8]/SectionHeading[0]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Timeline[8]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 584.271, + "placementX" : 30.0, + "placementY" : 584.271, + "placementWidth" : 68.525, + "placementHeight" : 27.409, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 68.525, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Timeline[8]/SectionHeading[0]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Timeline[8]/SectionHeading[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 586.871, + "placementX" : 30.0, + "placementY" : 586.871, + "placementWidth" : 68.525, + "placementHeight" : 24.809, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 68.525, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Timeline[8]/SectionHeading[0]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Timeline[8]/SectionHeading[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 584.271, + "placementX" : 30.0, + "placementY" : 584.271, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Timeline[8]/TimelineTable[1]", + "entityName" : "TimelineTable", + "entityKind" : "TableNode", + "parentPath" : "Proposal[0]/Timeline[8]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 405.621, + "placementX" : 30.0, + "placementY" : 405.621, + "placementWidth" : 535.276, + "placementHeight" : 164.95, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 164.95, + "margin" : { + "top" : 13.7, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]", + "entityName" : "MoneyBand", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]", + "childIndex" : 9, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 164.512, + "placementX" : 30.0, + "placementY" : 164.512, + "placementWidth" : 535.276, + "placementHeight" : 223.309, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 223.309, + "margin" : { + "top" : 17.8, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]", + "entityName" : "InvestmentColumn", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/MoneyBand[9]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 30.0, + "computedY" : 164.512, + "placementX" : 30.0, + "placementY" : 164.512, + "placementWidth" : 319.024, + "placementHeight" : 223.309, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 319.024, + "contentHeight" : 223.309, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]/SectionHeading[0]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 360.412, + "placementX" : 30.0, + "placementY" : 360.412, + "placementWidth" : 85.2, + "placementHeight" : 27.409, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 85.2, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]/SectionHeading[0]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]/SectionHeading[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 363.012, + "placementX" : 30.0, + "placementY" : 363.012, + "placementWidth" : 85.2, + "placementHeight" : 24.809, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 85.2, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]/SectionHeading[0]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]/SectionHeading[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 30.0, + "computedY" : 360.412, + "placementX" : 30.0, + "placementY" : 360.412, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]/InvestmentTable[1]", + "entityName" : "InvestmentTable", + "entityKind" : "TableNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/InvestmentColumn[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 30.0, + "computedY" : 164.512, + "placementX" : 30.0, + "placementY" : 164.512, + "placementWidth" : 319.024, + "placementHeight" : 182.2, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 319.024, + "contentHeight" : 182.2, + "margin" : { + "top" : 13.7, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]", + "entityName" : "TermsColumn", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/MoneyBand[9]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 388.635, + "computedY" : 211.012, + "placementX" : 388.635, + "placementY" : 211.012, + "placementWidth" : 176.54, + "placementHeight" : 176.809, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 176.54, + "contentHeight" : 176.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/SectionHeading[0]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 388.635, + "computedY" : 360.412, + "placementX" : 388.635, + "placementY" : 360.412, + "placementWidth" : 48.248, + "placementHeight" : 27.409, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 48.248, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/SectionHeading[0]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/SectionHeading[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 388.635, + "computedY" : 363.012, + "placementX" : 388.635, + "placementY" : 363.012, + "placementWidth" : 48.248, + "placementHeight" : 24.809, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 48.248, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/SectionHeading[0]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/SectionHeading[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 388.635, + "computedY" : 360.412, + "placementX" : 388.635, + "placementY" : 360.412, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]", + "entityName" : "TermsList", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 388.635, + "computedY" : 211.012, + "placementX" : 388.635, + "placementY" : 211.012, + "placementWidth" : 176.54, + "placementHeight" : 149.4, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 176.54, + "contentHeight" : 149.4, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 9.5, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 388.635, + "computedY" : 325.092, + "placementX" : 388.635, + "placementY" : 325.092, + "placementWidth" : 175.09, + "placementHeight" : 25.82, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 175.09, + "contentHeight" : 25.82, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 388.635, + "computedY" : 291.672, + "placementX" : 388.635, + "placementY" : 291.672, + "placementWidth" : 170.41, + "placementHeight" : 25.82, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 170.41, + "contentHeight" : 25.82, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 388.635, + "computedY" : 258.252, + "placementX" : 388.635, + "placementY" : 258.252, + "placementWidth" : 176.54, + "placementHeight" : 25.82, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 176.54, + "contentHeight" : 25.82, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]/ParagraphNode[3]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/MoneyBand[9]/TermsColumn[1]/TermsList[1]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 388.635, + "computedY" : 211.012, + "placementX" : 388.635, + "placementY" : 211.012, + "placementWidth" : 166.306, + "placementHeight" : 39.64, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 166.306, + "contentHeight" : 39.64, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]", + "entityName" : "Acceptance", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]", + "childIndex" : 10, + "depth" : 2, + "layer" : 2, + "computedX" : 30.0, + "computedY" : 60.004, + "placementX" : 30.0, + "placementY" : 60.004, + "placementWidth" : 535.276, + "placementHeight" : 86.709, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 535.276, + "contentHeight" : 86.709, + "margin" : { + "top" : 17.8, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 9.0, + "right" : 9.0, + "bottom" : 9.0, + "left" : 9.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]", + "entityName" : "AcceptanceBody", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Acceptance[10]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 39.0, + "computedY" : 69.004, + "placementX" : 39.0, + "placementY" : 69.004, + "placementWidth" : 517.276, + "placementHeight" : 68.709, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 517.276, + "contentHeight" : 68.709, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 9.0, + "bottom" : 0.0, + "left" : 9.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SectionHeading[0]", + "entityName" : "SectionHeading", + "entityKind" : "SectionNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 48.0, + "computedY" : 110.304, + "placementX" : 48.0, + "placementY" : 110.304, + "placementWidth" : 86.814, + "placementHeight" : 27.409, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 86.814, + "contentHeight" : 27.409, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SectionHeading[0]/SectionHeadingTitle[0]", + "entityName" : "SectionHeadingTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SectionHeading[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 48.0, + "computedY" : 112.904, + "placementX" : 48.0, + "placementY" : 112.904, + "placementWidth" : 86.814, + "placementHeight" : 24.809, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 86.814, + "contentHeight" : 24.809, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SectionHeading[0]/SectionHeadingRule[1]", + "entityName" : "SectionHeadingRule", + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SectionHeading[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 48.0, + "computedY" : 110.304, + "placementX" : 48.0, + "placementY" : 110.304, + "placementWidth" : 25.693, + "placementHeight" : 1.6, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 25.693, + "contentHeight" : 1.6, + "margin" : { + "top" : 1.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 48.0, + "computedY" : 88.804, + "placementX" : 48.0, + "placementY" : 88.804, + "placementWidth" : 432.25, + "placementHeight" : 12.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 432.25, + "contentHeight" : 12.0, + "margin" : { + "top" : 9.5, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "entityName" : "SignatureFields", + "entityKind" : "RowNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 48.0, + "computedY" : 69.004, + "placementX" : 48.0, + "placementY" : 69.004, + "placementWidth" : 499.276, + "placementHeight" : 19.8, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 499.276, + "contentHeight" : 19.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 9.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 48.0, + "computedY" : 69.004, + "placementX" : 48.0, + "placementY" : 69.004, + "placementWidth" : 51.759, + "placementHeight" : 10.8, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 51.759, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/LineNode[1]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 103.759, + "computedY" : 69.004, + "placementX" : 103.759, + "placementY" : 69.004, + "placementWidth" : 128.36, + "placementHeight" : 1.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 128.36, + "contentHeight" : 1.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/SpacerNode[2]", + "entityName" : null, + "entityKind" : "SpacerNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 236.119, + "computedY" : 69.004, + "placementX" : 236.119, + "placementY" : 69.004, + "placementWidth" : 7.5, + "placementHeight" : 0.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 7.5, + "contentHeight" : 0.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/ParagraphNode[3]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 247.619, + "computedY" : 69.004, + "placementX" : 247.619, + "placementY" : 69.004, + "placementWidth" : 39.753, + "placementHeight" : 10.8, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 39.753, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/LineNode[4]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 4, + "depth" : 5, + "layer" : 5, + "computedX" : 291.372, + "computedY" : 69.004, + "placementX" : 291.372, + "placementY" : 69.004, + "placementWidth" : 132.135, + "placementHeight" : 1.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 132.135, + "contentHeight" : 1.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/SpacerNode[5]", + "entityName" : null, + "entityKind" : "SpacerNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 5, + "depth" : 5, + "layer" : 5, + "computedX" : 427.508, + "computedY" : 69.004, + "placementX" : 427.508, + "placementY" : 69.004, + "placementWidth" : 7.5, + "placementHeight" : 0.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 7.5, + "contentHeight" : 0.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/ParagraphNode[6]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 6, + "depth" : 5, + "layer" : 5, + "computedX" : 439.008, + "computedY" : 69.004, + "placementX" : 439.008, + "placementY" : 69.004, + "placementWidth" : 21.555, + "placementHeight" : 10.8, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 21.555, + "contentHeight" : 10.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]/LineNode[7]", + "entityName" : null, + "entityKind" : "LineNode", + "parentPath" : "Proposal[0]/Acceptance[10]/AcceptanceBody[0]/SignatureFields[2]", + "childIndex" : 7, + "depth" : 5, + "layer" : 5, + "computedX" : 464.563, + "computedY" : 69.004, + "placementX" : 464.563, + "placementY" : 69.004, + "placementWidth" : 82.713, + "placementHeight" : 1.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 82.713, + "contentHeight" : 1.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + } ] +} diff --git a/qa/src/test/resources/visual-baselines/proposal-v2-layered/editorial_proposal-page-0.png b/qa/src/test/resources/visual-baselines/proposal-v2-layered/editorial_proposal-page-0.png new file mode 100644 index 000000000..b8e627b1e Binary files /dev/null and b/qa/src/test/resources/visual-baselines/proposal-v2-layered/editorial_proposal-page-0.png differ diff --git a/qa/src/test/resources/visual-baselines/proposal-v2-layered/editorial_proposal-page-1.png b/qa/src/test/resources/visual-baselines/proposal-v2-layered/editorial_proposal-page-1.png new file mode 100644 index 000000000..e36451411 Binary files /dev/null and b/qa/src/test/resources/visual-baselines/proposal-v2-layered/editorial_proposal-page-1.png differ diff --git a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialIcons.java b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialIcons.java new file mode 100644 index 000000000..33a66bfd8 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialIcons.java @@ -0,0 +1,66 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.document.dsl.ShapeContainerBuilder; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.style.ClipPolicy; +import com.demcha.compose.document.svg.SvgIcon; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Classpath loader for the Editorial Proposal icon set — the marks beside + * the at-a-glance facts and the check that opens every goal cell. + * + *

They ship inside the templates artifact under + * {@code templates/proposal/editorial/icons/} as SVG, so they scale with + * the box they are drawn into rather than being resampled. Parsed icons are + * cached per token, so a two-page proposal reads each file once per JVM.

+ */ +final class EditorialIcons { + + private static final String ICON_ROOT = "/templates/proposal/editorial/icons/"; + private static final Map CACHE = new ConcurrentHashMap<>(); + + private EditorialIcons() { + } + + /** + * Builds an icon node at a given width. + * + * @param token the icon token carried by the data + * @param width the drawn width; the height follows the icon's ratio + * @return the icon node + * @throws IllegalArgumentException when the token names no packaged icon + * — an icon token is data, so a wrong one is a data error + */ + static DocumentNode icon(String token, double width) { + // Named after the token: an icon swapped in the data then reaches the + // layout snapshot as a changed node path, not just as moved pixels. + return new ShapeContainerBuilder() + .name("Icon-" + token) + .rectangle(width, width) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .centerLeft(CACHE.computeIfAbsent(token, EditorialIcons::read).node(width)) + .build(); + } + + private static SvgIcon read(String token) { + String resourcePath = ICON_ROOT + token + ".svg"; + try (InputStream input = EditorialIcons.class.getResourceAsStream(resourcePath)) { + if (input == null) { + throw new IllegalArgumentException( + "Unknown editorial proposal icon token '" + token + + "' — no packaged icon at " + resourcePath + "."); + } + return SvgIcon.parse(new String(input.readAllBytes(), StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new UncheckedIOException( + "Failed to read editorial proposal icon: " + resourcePath, e); + } + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialPageOne.java b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialPageOne.java new file mode 100644 index 000000000..380322ea4 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialPageOne.java @@ -0,0 +1,307 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.document.dsl.PageFlowBuilder; +import com.demcha.compose.document.dsl.SectionBuilder; +import com.demcha.compose.document.dsl.ShapeContainerBuilder; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.node.LayerAlign; +import com.demcha.compose.document.node.RowVerticalAlign; +import com.demcha.compose.document.style.ClipPolicy; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentRowColumn; +import com.demcha.compose.document.style.DocumentStroke; +import com.demcha.compose.document.templates.data.proposal.ProposalGlance; +import com.demcha.compose.document.templates.data.proposal.ProposalGoals; +import com.demcha.compose.document.templates.data.proposal.ProposalScope; +import com.demcha.compose.document.templates.data.proposal.ProposalSummaryBlock; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalData; + +import java.util.List; + +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.BAND_TOP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.BODY; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.BODY_LEADING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.CONTENT_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FACT_DIVIDER_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FACT_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FACT_ICON; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FACT_LABEL; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FACT_NOTE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FACT_VALUE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FACT_VALUE_SIZE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_AFTER_RULE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_BEFORE_GOALS_HEADING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_META; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_PARAGRAPH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_TITLE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GLANCE_WEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GLANCE_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GOAL_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GOAL_ICON; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GOAL_TEXT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GOAL_TEXT_LINES; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.HAIRLINE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.HEADING_CAP_LEAD; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.HEADING_SIZE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.LABEL_SIZE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.META; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.META_SEPARATOR; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PANEL_BACKGROUND; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PANEL_PADDING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PANEL_RADIUS; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.RULE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.RULE_QUIET; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_BODY; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_DESC_WEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_LEADING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_NUMBER; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_NUMBER_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_ROW_PAD; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_TITLE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SCOPE_TITLE_SPLIT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SUMMARY_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SUMMARY_WEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TABLE_SIZE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TITLE_ACCENT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TITLE_INK; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TITLE_PITCH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TITLE_SIZE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.lineHeight; +import static com.demcha.compose.document.templates.proposal.presets.EditorialWidgets.sectionHeading; +import static com.demcha.compose.document.templates.proposal.presets.EditorialWidgets.stackedLines; + +/** + * Page one of the Editorial Proposal: the stacked title, the meta line, the + * summary beside the fact card, the goal cells, and the numbered scope list. + */ +final class EditorialPageOne { + + private EditorialPageOne() { + } + + static void compose(PageFlowBuilder page, StructuredProposalData data) { + renderTitleBlock(page, data); + renderTitleMeta(page, data); + renderSummaryBand(page, data); + renderGoalCells(page, data.goals()); + renderScopeOfWork(page, data.scope()); + } + + /** The three title lines, stacked on the reference's own pitch. */ + private static void renderTitleBlock(PageFlowBuilder page, StructuredProposalData data) { + page.addSection("TitleBlock", block -> { + block.margin(GAP_TITLE, 0f, 0f, 0f); + block.spacing(0); + block.add(stackedLines("TitleLines", CONTENT_WIDTH, TITLE_PITCH, TITLE_SIZE, + List.of(data.title().lead(), data.title().second(), data.title().third()), + List.of(TITLE_INK, TITLE_ACCENT, TITLE_ACCENT))); + }); + } + + /** Prepared-for, prepared-by and date, split by accent pipes. */ + private static void renderTitleMeta(PageFlowBuilder page, StructuredProposalData data) { + page.addSection("TitleMeta", section -> { + section.margin(GAP_META, 0f, 0f, 0f); + section.addParagraph(p -> p + .name("MetaLine") + .inlineText(data.meta().preparedFor(), META) + .inlineText(" | ", META_SEPARATOR) + .inlineText(data.meta().preparedBy(), META) + .inlineText(" | ", META_SEPARATOR) + .inlineText(data.meta().date(), META)); + }); + } + + /** The two-column band: summary and the goals heading left, fact card right. */ + private static void renderSummaryBand(PageFlowBuilder page, StructuredProposalData data) { + page.addRow("SummaryBand", row -> { + row.margin(DocumentInsets.top(BAND_TOP)); + row.verticalAlign(RowVerticalAlign.TOP) + .gap(SUMMARY_GAP) + .weights(SUMMARY_WEIGHT, GLANCE_WEIGHT); + row.addSection("SummaryColumn", column -> { + renderExecutiveSummary(column, data.executiveSummary()); + column.addSpacer(spacer -> spacer.height(GAP_BEFORE_GOALS_HEADING)); + column.add(sectionHeading(data.goals().heading())); + }); + row.addSection("GlanceColumn", column -> { + // The card's top edge lines up with the heading's CAP top, not + // with its line box, which starts HEADING_CAP_LEAD of the type + // size higher. Both children start at the band's top, so the + // card is padded down by the difference — stated once here + // rather than baked into BAND_TOP, which every band follows. + column.padding((float) (HEADING_SIZE * HEADING_CAP_LEAD - 1.6), 0f, 0f, 0f); + renderGlancePanel(column, data.glance()); + }); + }); + } + + private static void renderExecutiveSummary(SectionBuilder column, + ProposalSummaryBlock summary) { + column.spacing(0); + column.add(sectionHeading(summary.heading())); + List paragraphs = summary.paragraphs(); + for (int i = 0; i < paragraphs.size(); i++) { + String text = paragraphs.get(i); + float top = i == 0 ? GAP_AFTER_RULE : GAP_PARAGRAPH; + column.addParagraph(p -> p + .text(text) + .textStyle(BODY) + .lineSpacing(BODY_LEADING) + .margin(top, 0f, 0f, 0f)); + } + } + + /** + * The fact card. Unlike its teal sibling the card is untitled — the + * data's glance heading is not drawn — and its facts are divided by + * quiet rules inside a stroked panel. + */ + private static void renderGlancePanel(SectionBuilder column, ProposalGlance glance) { + List facts = glance.facts(); + double inner = GLANCE_WIDTH - 2 * PANEL_PADDING; + column.addSection("GlancePanel", panel -> { + panel.spacing(0).softPanel(PANEL_BACKGROUND, PANEL_RADIUS, PANEL_PADDING, + DocumentStroke.of(RULE_QUIET, HAIRLINE)); + for (int i = 0; i < facts.size(); i++) { + panel.add(renderGlanceFact(facts.get(i), inner)); + if (i < facts.size() - 1) { + panel.addLine(line -> line + .fill() + .thickness(HAIRLINE) + .color(RULE_QUIET) + .margin(DocumentInsets.symmetric(FACT_DIVIDER_GAP, 0))); + } + } + }); + } + + /** + * One fact: the icon anchored left of a label-over-value stack. The + * container's height derives from the lines the fact actually has, so an + * optional note makes its own room. + */ + private static DocumentNode renderGlanceFact(ProposalGlance.Fact fact, double width) { + boolean hasNote = !fact.note().isBlank(); + double height = lineHeight(LABEL_SIZE) + + lineHeight(FACT_VALUE_SIZE) + + (hasNote ? lineHeight(LABEL_SIZE + 0.5) : 0); + + SectionBuilder text = new SectionBuilder(); + text.name("FactText"); + text.spacing(0); + text.addParagraph(p -> p.text(fact.label()).textStyle(FACT_LABEL)); + text.addParagraph(p -> p.text(fact.value()).textStyle(FACT_VALUE)); + if (hasNote) { + text.addParagraph(p -> p.text(fact.note()).textStyle(FACT_NOTE)); + } + + ShapeContainerBuilder container = new ShapeContainerBuilder() + .name("GlanceFact") + .rectangle(width, height) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE); + if (!fact.icon().isBlank()) { + container.position(EditorialIcons.icon(fact.icon(), FACT_ICON), + 0, 0, LayerAlign.CENTER_LEFT); + } + return container + .position(text.build(), FACT_ICON + FACT_GAP, 0, LayerAlign.CENTER_LEFT) + .build(); + } + + /** + * The goal cells, flattened into one row: the engine refuses a row inside + * a row cell, so the column widths carry the structure. A cell opens with + * the goal's own icon token, falling back to the band's — which is how + * this design marks every cell alike, since its goals name no token. + */ + private static void renderGoalCells(PageFlowBuilder page, ProposalGoals goals) { + List items = goals.items(); + if (items.isEmpty()) { + return; + } + double dividerHeight = GOAL_TEXT_LINES * lineHeight(TABLE_SIZE); + page.addRow("GoalCells", row -> { + row.margin(DocumentInsets.top(BAND_TOP)); + row.verticalAlign(RowVerticalAlign.TOP).gap(GOAL_GAP); + row.columns(goalColumns(items.size())); + for (int i = 0; i < items.size(); i++) { + if (i > 0) { + row.addLine(line -> line + .vertical(dividerHeight) + .thickness(HAIRLINE) + .color(RULE)); + } + ProposalGoals.Goal goal = items.get(i); + // The goal's own token when it carries one; the band's token + // otherwise, which is how this design marks every cell the + // same. A goal that names neither keeps the column mapping of + // the flattened row with a spacer. + String mark = goal.icon().isBlank() ? goals.icon() : goal.icon(); + if (mark.isBlank()) { + row.addSpacer(GOAL_ICON); + } else { + row.add(EditorialIcons.icon(mark, GOAL_ICON)); + } + row.addParagraph(p -> p + .text(goal.text()) + .textStyle(GOAL_TEXT) + .lineSpacing(BODY_LEADING)); + } + }); + } + + private static DocumentRowColumn[] goalColumns(int goalCount) { + DocumentRowColumn[] columns = new DocumentRowColumn[goalCount * 2 + (goalCount - 1)]; + int at = 0; + for (int i = 0; i < goalCount; i++) { + if (i > 0) { + columns[at++] = DocumentRowColumn.fixed(HAIRLINE); + } + columns[at++] = DocumentRowColumn.fixed(GOAL_ICON); + columns[at++] = DocumentRowColumn.weight(1); + } + return columns; + } + + /** + * The numbered scope list: rows plus hairlines. The ordinal is plain + * accent text — the teal sibling encloses the same number in a pill. + */ + private static void renderScopeOfWork(PageFlowBuilder page, ProposalScope scope) { + double titleWidth = + CONTENT_WIDTH * SCOPE_TITLE_SPLIT - SCOPE_NUMBER_WIDTH - 2 * SCOPE_GAP; + page.addSection("ScopeOfWork", section -> { + section.margin(BAND_TOP, 0f, 0f, 0f); + section.spacing(0); + section.add(sectionHeading(scope.heading())); + section.addLine(line -> line + .fill() + .thickness(HAIRLINE) + .color(RULE) + .margin(DocumentInsets.top(GAP_AFTER_RULE))); + List items = scope.items(); + for (int i = 0; i < items.size(); i++) { + ProposalScope.Item item = items.get(i); + section.addRow("ScopeRow" + item.number(), row -> { + row.verticalAlign(RowVerticalAlign.TOP) + .gap(SCOPE_GAP) + .padding(DocumentInsets.symmetric(SCOPE_ROW_PAD, 0)) + .columns(DocumentRowColumn.fixed(SCOPE_NUMBER_WIDTH), + DocumentRowColumn.fixed(titleWidth), + DocumentRowColumn.fixed(CONTENT_WIDTH * SCOPE_DESC_WEIGHT)); + row.addParagraph(p -> p.text(item.number()).textStyle(SCOPE_NUMBER)); + row.addParagraph(p -> p.text(item.title()).textStyle(SCOPE_TITLE)); + row.addParagraph(p -> p + .text(item.description()) + .textStyle(SCOPE_BODY) + .lineSpacing(SCOPE_LEADING)); + }); + if (i < items.size() - 1) { + section.addLine(line -> line.fill().thickness(HAIRLINE).color(RULE)); + } + } + }); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialPageTwo.java b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialPageTwo.java new file mode 100644 index 000000000..a99370f96 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialPageTwo.java @@ -0,0 +1,360 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.document.dsl.PageFlowBuilder; +import com.demcha.compose.document.dsl.ParagraphBuilder; +import com.demcha.compose.document.dsl.RowBuilder; +import com.demcha.compose.document.dsl.SectionBuilder; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.node.RowVerticalAlign; +import com.demcha.compose.document.style.DocumentColor; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentRowColumn; +import com.demcha.compose.document.style.DocumentStroke; +import com.demcha.compose.document.style.DocumentTextStyle; +import com.demcha.compose.document.table.DocumentTableCell; +import com.demcha.compose.document.table.DocumentTableColumn; +import com.demcha.compose.document.table.DocumentTableStyle; +import com.demcha.compose.document.table.DocumentTableTextAnchor; +import com.demcha.compose.document.templates.data.proposal.ProposalAcceptance; +import com.demcha.compose.document.templates.data.proposal.ProposalDeliverables; +import com.demcha.compose.document.templates.data.proposal.ProposalInvestment; +import com.demcha.compose.document.templates.data.proposal.ProposalPhaseGrid; +import com.demcha.compose.document.templates.data.proposal.ProposalTermsBlock; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalData; + +import java.util.List; + +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.ACCENT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.ACCEPTANCE_FIELD_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.ACCEPTANCE_PADDING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.ACCEPTANCE_SIDE_PADDING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.BAND_TOP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.BODY; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.BODY_LEADING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.CONTENT_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.DELIVERABLES_COLUMN_WEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.DELIVERABLES_LEFT_WEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_AFTER_RULE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_BEFORE_TABLE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_BULLET; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_PAGE_TWO_OPENING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.HAIRLINE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INK; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INVESTMENT_EMPHASIS_PAD; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INVESTMENT_LABEL_SPLIT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INVESTMENT_ROW_PAD; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INVESTMENT_TOTAL_PAD; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INVESTMENT_WEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INVESTMENT_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.MONEY_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PANEL_BACKGROUND; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PANEL_RADIUS; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.RULE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.RULE_QUIET; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SIGNATURE_LABEL; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SIGNATURE_LABEL_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SIGNATURE_RULE_WEIGHTS; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SIGNATURE_SPACER; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SUBTOTAL_FILL; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TABLE_BODY; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TABLE_BODY_BOLD; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TABLE_CELL_INSET; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TABLE_HEADER; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TERMS_WEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TIMELINE_ROW_PAD; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TIMELINE_WEIGHTS; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.TOTAL_TEXT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialWidgets.renderBullet; +import static com.demcha.compose.document.templates.proposal.presets.EditorialWidgets.sectionHeading; + +/** + * Page two of the Editorial Proposal: the deliverable columns, the phase + * grid, the investment / terms band, and the signing card. + */ +final class EditorialPageTwo { + + private EditorialPageTwo() { + } + + static void compose(PageFlowBuilder page, StructuredProposalData data) { + renderDeliverables(page, data.deliverables()); + renderTimelineTable(page, data.timeline()); + renderMoneyBand(page, data); + renderAcceptance(page, data.acceptance()); + } + + /** Heading plus two bullet columns of measured width. */ + private static void renderDeliverables(PageFlowBuilder page, + ProposalDeliverables deliverables) { + page.addSection("Deliverables", section -> { + section.margin(GAP_PAGE_TWO_OPENING, 0f, 0f, 0f); + section.spacing(0); + section.add(sectionHeading(deliverables.heading())); + section.addRow("DeliverableColumns", row -> { + row.verticalAlign(RowVerticalAlign.TOP) + .gap(0) + .padding(DocumentInsets.top(GAP_AFTER_RULE)) + // Fixed, not weights: weights would divide the whole + // band between the two columns and neither would wrap + // where the reference wraps. The left column places the + // right one; the right one is its own measure, and the + // rest of the band stays empty as the reference leaves it. + .columns(DocumentRowColumn.fixed( + CONTENT_WIDTH * DELIVERABLES_LEFT_WEIGHT), + DocumentRowColumn.fixed( + CONTENT_WIDTH * DELIVERABLES_COLUMN_WEIGHT)); + row.addSection("DeliverablesLeft", column -> { + column.spacing(GAP_BULLET); + deliverables.leftColumn().forEach(item -> renderBullet(column, item)); + }); + row.addSection("DeliverablesRight", column -> { + column.spacing(GAP_BULLET); + deliverables.rightColumn().forEach(item -> renderBullet(column, item)); + }); + }); + }); + } + + /** + * The phase grid. Requires one authored header per rendered column, and + * is skipped entirely when the data carries no phases. + * + *

The two single-line columns are centred in their row rather than + * sat on its first line; the prose columns keep TOP because they are + * what makes the row tall, so centring them would be a no-op.

+ */ + private static void renderTimelineTable(PageFlowBuilder page, ProposalPhaseGrid timeline) { + if (timeline.phases().isEmpty()) { + return; + } + List headers = timeline.columnHeaders(); + if (headers.size() != TIMELINE_WEIGHTS.length) { + throw new IllegalArgumentException( + "The phase grid renders " + TIMELINE_WEIGHTS.length + + " columns and needs exactly one header per column; " + + "columnHeaders carries " + headers.size() + "."); + } + DocumentTableStyle headerStyle = DocumentTableStyle.builder() + .fillColor(INK) + .stroke(DocumentStroke.of(INK, HAIRLINE)) + .padding(DocumentInsets.symmetric(7, TABLE_CELL_INSET)) + .textStyle(TABLE_HEADER) + .textAnchor(DocumentTableTextAnchor.CENTER_LEFT) + .build(); + DocumentTableStyle cellStyle = DocumentTableStyle.builder() + .stroke(DocumentStroke.of(RULE, HAIRLINE)) + .padding(DocumentInsets.symmetric(TIMELINE_ROW_PAD, TABLE_CELL_INSET)) + .textStyle(TABLE_BODY) + .textAnchor(DocumentTableTextAnchor.TOP_LEFT) + .lineSpacing(BODY_LEADING) + .build(); + DocumentTableStyle centredCellStyle = DocumentTableStyle.builder() + .stroke(DocumentStroke.of(RULE, HAIRLINE)) + .padding(DocumentInsets.symmetric(TIMELINE_ROW_PAD, TABLE_CELL_INSET)) + .textStyle(TABLE_BODY) + .textAnchor(DocumentTableTextAnchor.CENTER_LEFT) + .build(); + + page.addSection("Timeline", section -> { + section.margin(BAND_TOP, 0f, 0f, 0f); + section.spacing(0); + section.add(sectionHeading(timeline.heading())); + section.addTable(table -> { + table.name("TimelineTable") + .width(CONTENT_WIDTH) + .margin(DocumentInsets.top(GAP_BEFORE_TABLE)) + .columns(DocumentTableColumn.fixed(CONTENT_WIDTH * TIMELINE_WEIGHTS[0]), + DocumentTableColumn.fixed(CONTENT_WIDTH * TIMELINE_WEIGHTS[1]), + DocumentTableColumn.fixed(CONTENT_WIDTH * TIMELINE_WEIGHTS[2]), + DocumentTableColumn.fixed(CONTENT_WIDTH * TIMELINE_WEIGHTS[3])) + .defaultCellStyle(cellStyle); + table.headerCells( + DocumentTableCell.text(headers.get(0)).withStyle(headerStyle), + DocumentTableCell.text(headers.get(1)).withStyle(headerStyle), + DocumentTableCell.text(headers.get(2)).withStyle(headerStyle), + DocumentTableCell.text(headers.get(3)).withStyle(headerStyle)); + for (ProposalPhaseGrid.Phase phase : timeline.phases()) { + table.rowCells( + DocumentTableCell.text(phase.number() + " " + phase.name()) + .withStyle(centredCellStyle), + DocumentTableCell.node(wrappingCell(phase.focus())) + .withStyle(cellStyle), + DocumentTableCell.text(phase.duration()) + .withStyle(centredCellStyle), + DocumentTableCell.node(wrappingCell(phase.output())) + .withStyle(cellStyle)); + } + table.repeatHeader(); + }); + }); + } + + /** A table cell that has to wrap: a composed paragraph wraps to its column. */ + private static DocumentNode wrappingCell(String text) { + return new ParagraphBuilder() + .name("Cell") + .text(text) + .textStyle(TABLE_BODY) + .lineSpacing(BODY_LEADING) + .build(); + } + + /** The two-column money band: the priced table left, the terms right. */ + private static void renderMoneyBand(PageFlowBuilder page, StructuredProposalData data) { + page.addRow("MoneyBand", row -> { + row.margin(DocumentInsets.top(BAND_TOP)); + row.verticalAlign(RowVerticalAlign.TOP) + .gap(MONEY_GAP) + .weights(INVESTMENT_WEIGHT, TERMS_WEIGHT); + row.addSection("InvestmentColumn", + column -> renderInvestmentTable(column, data.investment())); + row.addSection("TermsColumn", column -> renderTerms(column, data.terms())); + }); + } + + /** The priced block; the total band closes it in the accent. */ + private static void renderInvestmentTable(SectionBuilder column, + ProposalInvestment investment) { + double labelWidth = INVESTMENT_WIDTH * INVESTMENT_LABEL_SPLIT; + double amountWidth = INVESTMENT_WIDTH - labelWidth; + + DocumentTableStyle headerLabel = investmentStyle(INK, TABLE_HEADER, + DocumentTableTextAnchor.CENTER_LEFT, INVESTMENT_ROW_PAD + 1.5, INK); + DocumentTableStyle headerAmount = investmentStyle(INK, TABLE_HEADER, + DocumentTableTextAnchor.CENTER_RIGHT, INVESTMENT_ROW_PAD + 1.5, INK); + DocumentTableStyle rowLabel = investmentStyle(null, TABLE_BODY, + DocumentTableTextAnchor.CENTER_LEFT, INVESTMENT_ROW_PAD, RULE_QUIET); + DocumentTableStyle rowAmount = investmentStyle(null, TABLE_BODY, + DocumentTableTextAnchor.CENTER_RIGHT, INVESTMENT_ROW_PAD, RULE_QUIET); + DocumentTableStyle subtotalLabel = investmentStyle(SUBTOTAL_FILL, TABLE_BODY_BOLD, + DocumentTableTextAnchor.CENTER_LEFT, INVESTMENT_EMPHASIS_PAD, RULE_QUIET); + DocumentTableStyle subtotalAmount = investmentStyle(SUBTOTAL_FILL, TABLE_BODY_BOLD, + DocumentTableTextAnchor.CENTER_RIGHT, INVESTMENT_EMPHASIS_PAD, RULE_QUIET); + DocumentTableStyle optionalAmount = investmentStyle(null, TABLE_BODY_BOLD, + DocumentTableTextAnchor.CENTER_RIGHT, INVESTMENT_ROW_PAD, RULE_QUIET); + DocumentTableStyle totalLabel = investmentStyle(ACCENT, TOTAL_TEXT, + DocumentTableTextAnchor.CENTER_LEFT, INVESTMENT_TOTAL_PAD, ACCENT); + DocumentTableStyle totalAmount = investmentStyle(ACCENT, TOTAL_TEXT, + DocumentTableTextAnchor.CENTER_RIGHT, INVESTMENT_TOTAL_PAD, ACCENT); + + column.spacing(0); + column.add(sectionHeading(investment.heading())); + column.addTable(table -> { + table.name("InvestmentTable") + .width(INVESTMENT_WIDTH) + .margin(DocumentInsets.top(GAP_BEFORE_TABLE)) + .columns(DocumentTableColumn.fixed(labelWidth), + DocumentTableColumn.fixed(amountWidth)) + .defaultCellStyle(rowLabel); + table.headerCells( + DocumentTableCell.text(investment.itemHeader()).withStyle(headerLabel), + DocumentTableCell.text(investment.amountHeader()).withStyle(headerAmount)); + for (ProposalInvestment.Row line : investment.rows()) { + switch (line.role()) { + case SUBTOTAL -> table.rowCells( + DocumentTableCell.text(line.label()).withStyle(subtotalLabel), + DocumentTableCell.text(line.amount()).withStyle(subtotalAmount)); + case OPTIONAL -> table.rowCells( + DocumentTableCell.text(line.label()).withStyle(rowLabel), + DocumentTableCell.text(line.amount()).withStyle(optionalAmount)); + default -> table.rowCells( + DocumentTableCell.text(line.label()).withStyle(rowLabel), + DocumentTableCell.text(line.amount()).withStyle(rowAmount)); + } + } + table.rowCells( + DocumentTableCell.text(investment.totalLabel()).withStyle(totalLabel), + DocumentTableCell.text(investment.totalAmount()).withStyle(totalAmount)); + table.repeatHeader(); + }); + } + + /** One investment cell style; {@code fill} may be null for the plain rows. */ + private static DocumentTableStyle investmentStyle(DocumentColor fill, + DocumentTextStyle text, + DocumentTableTextAnchor anchor, + double verticalPad, + DocumentColor strokeColor) { + DocumentTableStyle.Builder builder = DocumentTableStyle.builder() + .stroke(DocumentStroke.of(strokeColor, HAIRLINE)) + .padding(DocumentInsets.symmetric(verticalPad, TABLE_CELL_INSET)) + .textStyle(text) + .textAnchor(anchor); + if (fill != null) { + builder.fillColor(fill); + } + return builder.build(); + } + + /** Heading plus the bulleted terms, reusing the deliverables bullet. */ + private static void renderTerms(SectionBuilder column, ProposalTermsBlock terms) { + column.spacing(0); + column.add(sectionHeading(terms.heading())); + column.addSection("TermsList", list -> { + list.spacing(GAP_BULLET).padding(GAP_AFTER_RULE, 0f, 0f, 0f); + terms.items().forEach(item -> renderBullet(list, item)); + }); + } + + /** + * The signing card. {@code softPanel} carries one padding for all four + * sides, so the wider horizontal inset the reference uses belongs to the + * body section inside it. + */ + private static void renderAcceptance(PageFlowBuilder page, ProposalAcceptance acceptance) { + double side = ACCEPTANCE_SIDE_PADDING - ACCEPTANCE_PADDING; + page.addSection("Acceptance", card -> { + card.margin(BAND_TOP, 0f, 0f, 0f); + card.spacing(0).keepTogether().softPanel(PANEL_BACKGROUND, PANEL_RADIUS, + ACCEPTANCE_PADDING, DocumentStroke.of(RULE, HAIRLINE)); + card.addSection("AcceptanceBody", body -> { + body.spacing(0).padding(0f, (float) side, 0f, (float) side); + body.add(sectionHeading(acceptance.heading())); + body.addParagraph(p -> p + .text(acceptance.statement()) + .textStyle(BODY) + .lineSpacing(BODY_LEADING) + .margin(GAP_AFTER_RULE, 0f, 0f, 0f)); + if (!acceptance.fields().isEmpty()) { + body.addRow("SignatureFields", + row -> renderSignatureFields(row, acceptance.fields())); + } + }); + }); + } + + /** label, rule, spacer, label, rule, spacer, label, rule. */ + private static void renderSignatureFields(RowBuilder row, List fields) { + DocumentRowColumn[] columns = new DocumentRowColumn[fields.size() * 3 - 1]; + int at = 0; + for (int i = 0; i < fields.size(); i++) { + if (i > 0) { + columns[at++] = DocumentRowColumn.fixed(SIGNATURE_SPACER); + } + columns[at++] = DocumentRowColumn.auto(); + columns[at++] = DocumentRowColumn.weight(signatureRuleWeight(i, fields.size())); + } + row.verticalAlign(RowVerticalAlign.BOTTOM) + .gap(SIGNATURE_LABEL_GAP) + .padding(DocumentInsets.top(ACCEPTANCE_FIELD_GAP)) + .columns(columns); + for (int i = 0; i < fields.size(); i++) { + if (i > 0) { + row.addSpacer(SIGNATURE_SPACER); + } + String field = fields.get(i); + row.addParagraph(p -> p.text(field).textStyle(SIGNATURE_LABEL)); + row.addLine(line -> line.fill().thickness(HAIRLINE).color(INK)); + } + } + + /** + * The measured rule widths apply to the three-field card the reference + * sets; any other count divides the row evenly. + */ + private static double signatureRuleWeight(int index, int fieldCount) { + return fieldCount == SIGNATURE_RULE_WEIGHTS.length + ? SIGNATURE_RULE_WEIGHTS[index] + : 1.0 / fieldCount; + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposal.java b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposal.java new file mode 100644 index 000000000..1ecc0b218 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialProposal.java @@ -0,0 +1,162 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.api.PageBackgroundFill; +import com.demcha.compose.document.output.DocumentHeaderFooter; +import com.demcha.compose.document.output.DocumentHeaderFooterZone; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.templates.api.DocumentTemplate; +import com.demcha.compose.document.templates.data.proposal.ProposalBrand; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalData; +import com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec; + +import java.util.List; +import java.util.Objects; + +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.CONTENT_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FOOTER_BAND; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FOOTER_RULE_Y; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FOOTER_TEXT_SIZE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.FOOTER_ZONE_HEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.HAIRLINE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INK; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.MARGIN_SIDE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.MARGIN_TOP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PAGE_BACKGROUND; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PAGE_HEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PAGE_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.RULE; + +/** + * Editorial Proposal — the second structured proposal preset: a two-page + * business proposal set in a serif display face with an orange accent. + * + *

Page one opens with the masthead — a drawn brand mark, the stacked + * wordmark, the tracked document label — then the three title lines, the + * meta line, the executive summary beside an at-a-glance fact card, the + * goal cells, and the numbered scope list. Page two repeats the masthead + * and carries the deliverable columns, the phase grid, the investment / + * terms band, and the signing card.

+ * + *

What sets it apart from {@link NorthlineProposal}, which renders the + * same {@link StructuredProposalDocumentSpec}: section headings are set in + * the display serif over a short accent rule rather than in the body sans + * inside an icon badge, so the data's section icon tokens are not drawn; + * the brand mark is drawn from vector paths rather than set as a monogram + * letter; the fact card is untitled, so its heading is not drawn either; + * the scope ordinal is plain accent text rather than a filled pill; and the + * page foot is a hairline over the content width rather than a filled band. + * Both presets set their titles in the same display face.

+ * + *

Moving a document between the two presets is a + * one-line change in the code and two things to check in the data. Icon + * tokens are preset-scoped vocabulary — each preset packages its own set, + * and a token this one does not carry is reported as a data error; the four + * {@code fact-*} tokens are named alike in both sets, the badge and goal + * tokens are not. Heading text is drawn as authored, so a document written + * for the sibling's tracked capitals keeps them here, where this design + * sets its headings in title case.

+ * + *

The preset owns its session geometry — A4, the margins published as + * {@link #RECOMMENDED_MARGIN}, the near-white page fill — and draws the + * brand line and page numbers as footer chrome, so they repeat on every + * page. It issues no explicit page break: the page-two masthead is + * {@code keepWithNext}, which is what stops it being orphaned at the foot + * of page one, and a break issued after the compiler has already advanced + * would leave a blank page between the two.

+ */ +public final class EditorialProposal { + + /** + * Stable template identifier. + */ + public static final String ID = "proposal-editorial"; + + /** + * Human-readable display name. + */ + public static final String DISPLAY_NAME = "Editorial Proposal"; + + /** + * The side margin (in points) the preset sets. It is published so a + * caller can measure against the same frame; the preset applies its own + * margins inside {@code compose}, so callers leave the session + * unconfigured. + */ + public static final double RECOMMENDED_MARGIN = MARGIN_SIDE; + + private EditorialProposal() { + } + + /** + * Builds the preset. + * + * @return ready-to-use template + */ + public static DocumentTemplate create() { + return new Template(); + } + + private record Template() implements DocumentTemplate { + + @Override + public String id() { + return ID; + } + + @Override + public String displayName() { + return DISPLAY_NAME; + } + + @Override + public void compose(DocumentSession document, StructuredProposalDocumentSpec spec) { + Objects.requireNonNull(document, "document"); + StructuredProposalData data = Objects.requireNonNull(spec, "spec").proposal(); + + document.pageSize(PAGE_WIDTH, PAGE_HEIGHT) + // The bottom margin is the footer band: content stops + // above it, so nothing runs under the chrome. + .margin(new DocumentInsets(MARGIN_TOP, MARGIN_SIDE, + FOOTER_BAND, MARGIN_SIDE)) + .pageBackground(PAGE_BACKGROUND); + + renderChrome(document, data.brand()); + + document.pageFlow(page -> { + // spacing(0): flow spacing survives a page break, so a band + // opening a page would inherit a gap the first never had. + page.name("Proposal").spacing(0); + EditorialWidgets.renderMasthead(page, data.brand()); + EditorialPageOne.compose(page, data); + EditorialWidgets.renderMasthead(page, data.brand()); + EditorialPageTwo.compose(page, data); + }); + } + + /** + * The page foot: a hairline across the content width as a page-ratio + * background fill, and the brand line with the page number as + * FOOTER-zone chrome, both repeating on every page. The number is + * written {@code 0{page}} because the reference numbers its pages 01 + * and 02 and there is no zero-padded page-number style. + */ + private static void renderChrome(DocumentSession document, ProposalBrand brand) { + document.pageBackgrounds(List.of(new PageBackgroundFill( + MARGIN_SIDE / PAGE_WIDTH, + FOOTER_RULE_Y / PAGE_HEIGHT, + CONTENT_WIDTH / PAGE_WIDTH, + HAIRLINE / PAGE_HEIGHT, + RULE))); + + document.footer(DocumentHeaderFooter.builder() + .zone(DocumentHeaderFooterZone.FOOTER) + .height((float) FOOTER_ZONE_HEIGHT) + .leftText(brand.footerName() + " | " + brand.website()) + .rightText("0{page}") + .fontSize((float) FOOTER_TEXT_SIZE) + .textColor(INK) + .build()); + } + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialStyles.java b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialStyles.java new file mode 100644 index 000000000..88c310867 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialStyles.java @@ -0,0 +1,219 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.document.style.DocumentColor; +import com.demcha.compose.document.style.DocumentTextDecoration; +import com.demcha.compose.document.style.DocumentTextStyle; +import com.demcha.compose.font.FontName; + +/** + * The Editorial Proposal look: page geometry, the colour roles, the + * Spectral/Lato scale, and the measured widths every band works against. + * + *

Preset-local for the same reason as its sibling's tokens: every value + * was measured against the ported template's reference render, and no other + * family shares this look.

+ */ +final class EditorialStyles { + + private EditorialStyles() { + } + + // --- page --------------------------------------------------------------- + static final double PAGE_WIDTH = 595.276; // A4 portrait, points + static final double PAGE_HEIGHT = 841.890; + static final double MARGIN_SIDE = 30.0; + static final double MARGIN_TOP = 19.7; + static final double CONTENT_WIDTH = PAGE_WIDTH - 2 * MARGIN_SIDE; + static final double FOOTER_BAND = 49.0; + + // --- band splits, measured from the reference --------------------------- + static final double SUMMARY_WEIGHT = 0.60; + static final double GLANCE_WEIGHT = 0.338; + static final double SUMMARY_GAP = CONTENT_WIDTH * (1 - SUMMARY_WEIGHT - GLANCE_WEIGHT); + static final double INVESTMENT_WEIGHT = 0.596; + static final double TERMS_WEIGHT = 0.330; + static final double MONEY_GAP = CONTENT_WIDTH * (1 - INVESTMENT_WEIGHT - TERMS_WEIGHT); + static final double DELIVERABLES_LEFT_WEIGHT = 0.491; + static final double DELIVERABLES_COLUMN_WEIGHT = 0.362; + /** PHASE / FOCUS / DURATION / OUTPUT. */ + static final double[] TIMELINE_WEIGHTS = {0.222, 0.307, 0.179, 0.291}; + static final double SCOPE_TITLE_SPLIT = 0.430; + static final double SCOPE_DESC_WEIGHT = 0.532; + static final double INVESTMENT_LABEL_SPLIT = 0.64; + + static final double GLANCE_WIDTH = CONTENT_WIDTH * GLANCE_WEIGHT; + static final double INVESTMENT_WIDTH = CONTENT_WIDTH * INVESTMENT_WEIGHT; + + // --- independent dimensions --------------------------------------------- + static final double LOGO_WIDTH = 30.0; + static final double LOGO_HEIGHT = 26.0; + static final double LOGO_GAP = 9.0; + /** Wordmark line pitch, as a fraction of its type size. */ + static final double WORDMARK_LINE = 0.82; + static final double WORDMARK_WIDTH = CONTENT_WIDTH * 0.19; + static final double DOC_LABEL_WIDTH = CONTENT_WIDTH * 0.13; + static final double DOC_LABEL_RULE_WIDTH = CONTENT_WIDTH * 0.115; + static final double DOC_LABEL_INSET = 8.5; + static final double FACT_ICON = 20.0; + static final double FACT_GAP = 14.0; + static final double GOAL_ICON = 16.0; + static final double GOAL_GAP = 8.0; + static final int GOAL_TEXT_LINES = 3; + static final double PANEL_PADDING = 17.0; + static final double PANEL_RADIUS = 5.0; + static final double ACCEPTANCE_PADDING = 9.0; + static final double ACCEPTANCE_SIDE_PADDING = 18.0; + static final double SIGNATURE_LABEL_GAP = 4.0; + static final double SIGNATURE_FIELD_GAP = 15.5; + static final double SIGNATURE_SPACER = SIGNATURE_FIELD_GAP - 2 * SIGNATURE_LABEL_GAP; + /** Rule widths of the three signature fields the reference sets. */ + static final double[] SIGNATURE_RULE_WEIGHTS = {0.374, 0.385, 0.241}; + static final double SCOPE_NUMBER_WIDTH = 22.0; + static final double SCOPE_GAP = 12.0; + static final double HAIRLINE = 0.7; + static final double MASTHEAD_RULE = 1.1; + static final double HEADING_RULE_WIDTH = CONTENT_WIDTH * 0.048; + static final double HEADING_RULE_THICKNESS = 1.6; + + // --- vertical rhythm ----------------------------------------------------- + /** + * The gap above a band, carried by the band rather than by the page flow: + * flow spacing survives a page break, so a band opening a page would + * inherit a leading gap the first band never had. + */ + static final float BAND_TOP = 17.8f; + static final double GAP_MASTHEAD_RULE = 16.1; + static final float GAP_TITLE = 15.5f; + static final float GAP_META = 16.0f; + static final float GAP_PAGE_TWO_OPENING = 19.0f; + static final double GAP_HEADING = 1.0; + static final float GAP_AFTER_RULE = 9.5f; + static final float GAP_BEFORE_TABLE = 13.7f; + static final float GAP_PARAGRAPH = 9.0f; + static final double GAP_BEFORE_GOALS_HEADING = 26.5; + static final double FACT_DIVIDER_GAP = 7.1; + static final double SCOPE_ROW_PAD = 2.9; + static final double INVESTMENT_ROW_PAD = 4.0; + static final double INVESTMENT_EMPHASIS_PAD = 7.0; + static final double INVESTMENT_TOTAL_PAD = 5.4; + static final double TIMELINE_ROW_PAD = 7.0; + static final double TABLE_CELL_INSET = 10.0; + static final double ACCEPTANCE_FIELD_GAP = 9.0; + static final float GAP_BULLET = 7.6f; + static final double LIST_LEADING = 0.87; + + // --- type scale ---------------------------------------------------------- + static final double BODY_SIZE = 10.0; + /** EXTRA leading in points (the engine adds it to the font's line height). */ + static final double BODY_LEADING = 3.05; + /** Lato line height as a multiple of the type size (measured). */ + static final double LATO_LINE = 1.213; + static final double TITLE_SIZE = 41.8; + static final double TITLE_PITCH = 41.9; + static final double HEADING_SIZE = 16.3; + static final double WORDMARK_SIZE = 16.1; + static final double WORDMARK_SUB_SIZE = 14.0; + static final double TABLE_SIZE = 9.0; + static final double LABEL_SIZE = 7.5; + static final double DOC_LABEL_SIZE = 8.3; + static final double META_SIZE = 10.5; + static final double FACT_VALUE_SIZE = 14.0; + static final double SCOPE_BODY_SIZE = 9.9; + static final double SCOPE_LEADING = 0.6; + static final double FOOTER_TEXT_SIZE = 8.5; + /** Helvetica cap height as a fraction of the type size. */ + static final double HELVETICA_CAP = 0.717; + /** + * Not the band height: the backend places the footer baseline at + * (height - fontSize) above the page edge, so this seats the cap band in + * the middle of the footer band. + */ + static final double FOOTER_ZONE_HEIGHT = + (FOOTER_BAND - FOOTER_TEXT_SIZE * HELVETICA_CAP) / 2 + FOOTER_TEXT_SIZE; + static final double FOOTER_RULE_Y = PAGE_HEIGHT - FOOTER_BAND; + /** How far a heading's line box starts above its cap top, as a fraction of the size. */ + static final double HEADING_CAP_LEAD = 0.42; + + // --- colour roles: named for the job, not the hue ------------------------ + static final DocumentColor ACCENT = DocumentColor.rgb(237, 76, 15); + static final DocumentColor INK = DocumentColor.rgb(35, 35, 35); + static final DocumentColor BODY_TEXT = DocumentColor.rgb(46, 46, 46); + static final DocumentColor MUTED_TEXT = DocumentColor.rgb(90, 90, 90); + static final DocumentColor PAGE_BACKGROUND = DocumentColor.rgb(254, 254, 254); + static final DocumentColor PANEL_BACKGROUND = DocumentColor.rgb(250, 246, 243); + static final DocumentColor SUBTOTAL_FILL = DocumentColor.rgb(243, 241, 239); + static final DocumentColor RULE = DocumentColor.rgb(216, 213, 210); + static final DocumentColor RULE_QUIET = DocumentColor.rgb(231, 227, 223); + static final DocumentColor ON_DARK = DocumentColor.rgb(255, 255, 255); + + static final FontName TITLE_FONT = FontName.SPECTRAL; + static final FontName BODY_FONT = FontName.LATO; + + // --- text roles ----------------------------------------------------------- + static final DocumentTextStyle TITLE_INK = + style(TITLE_FONT, TITLE_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle TITLE_ACCENT = + style(TITLE_FONT, TITLE_SIZE, DocumentTextDecoration.BOLD, ACCENT); + static final DocumentTextStyle SECTION_HEADING = + style(TITLE_FONT, HEADING_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle BODY = + style(BODY_FONT, BODY_SIZE, DocumentTextDecoration.DEFAULT, BODY_TEXT); + static final DocumentTextStyle META = + style(BODY_FONT, META_SIZE, DocumentTextDecoration.DEFAULT, BODY_TEXT); + static final DocumentTextStyle META_SEPARATOR = + style(BODY_FONT, META_SIZE, DocumentTextDecoration.DEFAULT, ACCENT); + static final DocumentTextStyle FACT_LABEL = + style(BODY_FONT, LABEL_SIZE, DocumentTextDecoration.BOLD, MUTED_TEXT); + static final DocumentTextStyle FACT_VALUE = + style(BODY_FONT, FACT_VALUE_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle FACT_NOTE = + style(BODY_FONT, LABEL_SIZE + 0.5, DocumentTextDecoration.DEFAULT, MUTED_TEXT); + static final DocumentTextStyle GOAL_TEXT = + style(BODY_FONT, TABLE_SIZE, DocumentTextDecoration.DEFAULT, BODY_TEXT); + static final DocumentTextStyle SCOPE_NUMBER = + style(BODY_FONT, TABLE_SIZE, DocumentTextDecoration.BOLD, ACCENT); + static final DocumentTextStyle SCOPE_TITLE = + style(BODY_FONT, TABLE_SIZE + 0.5, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle SCOPE_BODY = + style(BODY_FONT, SCOPE_BODY_SIZE, DocumentTextDecoration.DEFAULT, MUTED_TEXT); + static final DocumentTextStyle TABLE_HEADER = + style(BODY_FONT, TABLE_SIZE - 0.5, DocumentTextDecoration.BOLD, ON_DARK); + static final DocumentTextStyle TABLE_BODY = + style(BODY_FONT, TABLE_SIZE, DocumentTextDecoration.DEFAULT, BODY_TEXT); + static final DocumentTextStyle TABLE_BODY_BOLD = + style(BODY_FONT, TABLE_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle TOTAL_TEXT = + style(BODY_FONT, TABLE_SIZE + 1.5, DocumentTextDecoration.BOLD, ON_DARK); + static final DocumentTextStyle WORDMARK = + style(BODY_FONT, WORDMARK_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle WORDMARK_SUB = + style(BODY_FONT, WORDMARK_SUB_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle DOC_LABEL = + style(BODY_FONT, DOC_LABEL_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle SIGNATURE_LABEL = + style(BODY_FONT, TABLE_SIZE, DocumentTextDecoration.DEFAULT, INK); + + /** + * The height one line of body-scale text occupies: the font's own line + * height plus the additive leading. Multiplying the size by the leading + * is the wrong model and makes derived heights half again too tall. + * + * @param size the type size + * @return the line height in points + */ + static double lineHeight(double size) { + return size * LATO_LINE + BODY_LEADING; + } + + private static DocumentTextStyle style(FontName font, + double size, + DocumentTextDecoration decoration, + DocumentColor color) { + return DocumentTextStyle.builder() + .fontName(font) + .size(size) + .decoration(decoration) + .color(color) + .build(); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialWidgets.java b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialWidgets.java new file mode 100644 index 000000000..51ad20784 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/EditorialWidgets.java @@ -0,0 +1,224 @@ +package com.demcha.compose.document.templates.proposal.presets; + +import com.demcha.compose.document.dsl.LineBuilder; +import com.demcha.compose.document.dsl.PageFlowBuilder; +import com.demcha.compose.document.dsl.ParagraphBuilder; +import com.demcha.compose.document.dsl.PathBuilder; +import com.demcha.compose.document.dsl.SectionBuilder; +import com.demcha.compose.document.dsl.ShapeContainerBuilder; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.node.HorizontalAlign; +import com.demcha.compose.document.node.LayerAlign; +import com.demcha.compose.document.node.RowVerticalAlign; +import com.demcha.compose.document.node.TextAlign; +import com.demcha.compose.document.style.ClipPolicy; +import com.demcha.compose.document.style.DocumentColor; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentRowColumn; +import com.demcha.compose.document.style.DocumentTextIndent; +import com.demcha.compose.document.style.DocumentTextStyle; +import com.demcha.compose.document.svg.SvgPath; +import com.demcha.compose.document.templates.core.text.TextOrnaments; +import com.demcha.compose.document.templates.data.proposal.ProposalBrand; + +import java.util.List; + +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.ACCENT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.BODY; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.DOC_LABEL; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.DOC_LABEL_INSET; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.DOC_LABEL_RULE_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.DOC_LABEL_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_HEADING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.GAP_MASTHEAD_RULE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.HEADING_RULE_THICKNESS; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.HEADING_RULE_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.INK; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.LIST_LEADING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.LOGO_GAP; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.LOGO_HEIGHT; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.LOGO_WIDTH; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.MASTHEAD_RULE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.PAGE_BACKGROUND; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.SECTION_HEADING; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.WORDMARK; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.WORDMARK_LINE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.WORDMARK_SIZE; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.WORDMARK_SUB; +import static com.demcha.compose.document.templates.proposal.presets.EditorialStyles.WORDMARK_WIDTH; + +/** + * The building blocks the Editorial Proposal bands share: the masthead that + * opens every page, the drawn logo mark, the serif section heading over its + * accent rule, the bullet, and the stacked-line box both the wordmark and + * the title are set in. + */ +final class EditorialWidgets { + + private EditorialWidgets() { + } + + /** + * The masthead: the drawn mark, the stacked wordmark, the tracked + * document label over its accent rule, and the full-width rule beneath. + * + *

It is {@code keepWithNext}, which is what stops the page-two + * masthead from being orphaned at the foot of page one — the preset + * issues no explicit page break.

+ */ + static void renderMasthead(PageFlowBuilder page, ProposalBrand brand) { + page.addSection("Masthead", masthead -> { + masthead.spacing(0); + masthead.keepWithNext(); + masthead.addRow("MastheadRow", row -> { + row.verticalAlign(RowVerticalAlign.CENTER) + .gap(LOGO_GAP) + // Not auto(): a section's natural width is the width + // it is offered, so two auto columns would each claim + // the whole row. Both ends are measured strips. + .columns(DocumentRowColumn.fixed(LOGO_WIDTH), + DocumentRowColumn.fixed(WORDMARK_WIDTH), + DocumentRowColumn.weight(1), + DocumentRowColumn.fixed(DOC_LABEL_WIDTH)); + row.add(logoMark()); + // The wordmark stacks at 0.82 of its type size, tighter than + // the 1.21 Lato asks for, which is what makes it read as one + // mark rather than two words — and a section cannot carry the + // negative spacing that pitch would need. + row.add(stackedLines("Wordmark", WORDMARK_WIDTH, + WORDMARK_SIZE * WORDMARK_LINE, WORDMARK_SIZE, + List.of(brand.nameLine1(), brand.nameLine2()), + List.of(WORDMARK, WORDMARK_SUB))); + // A zero-width spacer: the row distributes by columns, and the + // weight(1) column above already holds the ends apart. + row.addSpacer(0); + row.addSection("DocumentLabel", label -> { + label.spacing(0); + label.padding(0f, (float) DOC_LABEL_INSET, 0f, 0f); + label.addParagraph(p -> p + .text(TextOrnaments.spacedUpper(brand.documentLabel())) + .textStyle(DOC_LABEL) + .align(TextAlign.RIGHT)); + // addAligned, not addLine: a section stacks children at the + // content width with no child alignment, and this rule sits + // flush RIGHT under the label. + label.addAligned(HorizontalAlign.RIGHT, new LineBuilder() + .name("DocumentLabelRule") + .horizontal(DOC_LABEL_RULE_WIDTH) + .thickness(HEADING_RULE_THICKNESS) + .color(ACCENT) + .margin(DocumentInsets.top(5)) + .build()); + }); + }); + masthead.addLine(line -> line + .fill() + .thickness(MASTHEAD_RULE) + .color(INK) + .margin(DocumentInsets.top(GAP_MASTHEAD_RULE))); + }); + } + + /** + * The brand mark, drawn as four stacked vector paths rather than loaded: + * an accent stem, an accent diagonal, a page-coloured slash that cuts it, + * and an ink stem. + */ + private static DocumentNode logoMark() { + return new ShapeContainerBuilder() + .name("LogoMark") + .rectangle(LOGO_WIDTH, LOGO_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .position(markPath("MarkStem", "M0,0 L14,0 L14,50 L0,50 Z", ACCENT), + 0, 0, LayerAlign.TOP_LEFT, 0) + .position(markPath("MarkDiagonal", "M13,0 L28,0 L48,50 L33,50 Z", ACCENT), + 0, 0, LayerAlign.TOP_LEFT, 1) + .position(markPath("MarkSlash", "M3,0 L8,0 L45,50 L40,50 Z", PAGE_BACKGROUND), + 0, 0, LayerAlign.TOP_LEFT, 2) + .position(markPath("MarkRightStem", "M40,0 L58,0 L58,50 L40,50 Z", INK), + 0, 0, LayerAlign.TOP_LEFT, 3) + .build(); + } + + private static DocumentNode markPath(String name, String d, DocumentColor fill) { + return new PathBuilder() + .name(name) + .size(LOGO_WIDTH, LOGO_HEIGHT) + .svg(SvgPath.parse(d, 0, 0, 58, 50)) + .fillColor(fill) + .build(); + } + + /** + * The heading every section opens with: the serif title over a short + * accent rule. Unlike its teal sibling there is no badge, so the data's + * section icon tokens are not read here. + * + * @param title the heading text + * @return the heading node, kept with whatever follows it + */ + static DocumentNode sectionHeading(String title) { + SectionBuilder heading = new SectionBuilder(); + heading.name("SectionHeading"); + heading.spacing(0); + heading.keepWithNext(); + heading.addParagraph(p -> p + .name("SectionHeadingTitle") + .text(title) + .textStyle(SECTION_HEADING)); + heading.addLine(line -> line + .name("SectionHeadingRule") + .horizontal(HEADING_RULE_WIDTH) + .thickness(HEADING_RULE_THICKNESS) + .color(ACCENT) + .margin(DocumentInsets.top(GAP_HEADING))); + return heading.build(); + } + + /** + * A bullet item: an inline accent dot, then the text, with a hanging + * indent so wrapped lines clear the dot. + */ + static void renderBullet(SectionBuilder host, String text) { + host.addParagraph(p -> p + .dot(3.6, ACCENT) + .inlineText(" " + text, BODY) + .bulletOffset(" ") + .indentStrategy(DocumentTextIndent.FROM_SECOND_LINE) + .lineSpacing(LIST_LEADING)); + } + + /** + * Lines stacked on an authored pitch: each line is anchored inside one + * container, because leading is additive and the engine rejects the + * negative value a tighter-than-natural pitch would need. + * + * @param name node name of the box and its lines + * @param width the box width + * @param pitch distance between line tops + * @param lastLineHeight height reserved for the final line + * @param texts the lines, in order + * @param styles one style per line + * @return the stacked box + */ + static DocumentNode stackedLines(String name, + double width, + double pitch, + double lastLineHeight, + List texts, + List styles) { + ShapeContainerBuilder box = new ShapeContainerBuilder() + .name(name) + .rectangle(width, (texts.size() - 1) * pitch + lastLineHeight) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE); + for (int i = 0; i < texts.size(); i++) { + DocumentNode line = new ParagraphBuilder() + .name(name + "Line" + (i + 1)) + .text(texts.get(i)) + .textStyle(styles.get(i)) + .build(); + box.position(line, 0, i * pitch, LayerAlign.TOP_LEFT); + } + return box.build(); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/package-info.java b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/package-info.java index 655ef0ec1..56bf35f33 100644 --- a/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/package-info.java +++ b/templates/src/main/java/com/demcha/compose/document/templates/proposal/presets/package-info.java @@ -1,16 +1,28 @@ /** - * Layered proposal presets — thin orchestrators that compose a proposal - * on a {@link com.demcha.compose.document.templates.core.theme.BrandTheme} - * plus the canonical DSL. + * Layered proposal presets — thin orchestrators that compose a proposal on + * the canonical DSL. * - *

This package mirrors {@code invoice.presets}: each preset is a - * {@code final} class with a {@code create(BrandTheme)} factory returning - * a {@link com.demcha.compose.document.templates.api.DocumentTemplate} - * parameterised on - * {@link com.demcha.compose.document.templates.data.proposal.ProposalDocumentSpec}. - * The presets read every visual value from the theme and reuse the shared - * {@code templates.core.*} layer; the proposal family does not own a theme - * type of its own.

+ *

Each preset is a {@code final} class whose {@code create} factory + * returns a + * {@link com.demcha.compose.document.templates.api.DocumentTemplate}, and + * the package holds two shapes of them:

+ * + *
    + *
  • Narrative presets take a {@code create(BrandTheme)} factory + * and are parameterised on + * {@link com.demcha.compose.document.templates.data.proposal.ProposalDocumentSpec}, + * reading every visual value from the theme + * ({@code ModernProposal}).
  • + *
  • Structured presets take a no-argument {@code create()} and + * are parameterised on + * {@link com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec}, + * carrying their measured geometry and palette as preset-local tokens + * because each reproduces one designed look rather than a themeable + * family ({@code NorthlineProposal}, {@code EditorialProposal}).
  • + *
+ * + *

Both shapes reuse the shared {@code templates.core.*} layer; the + * proposal family does not own a theme type of its own.

* * @since 2.0.0 */ diff --git a/templates/src/main/resources/templates/proposal/editorial/icons/fact-contact.svg b/templates/src/main/resources/templates/proposal/editorial/icons/fact-contact.svg new file mode 100644 index 000000000..301914753 --- /dev/null +++ b/templates/src/main/resources/templates/proposal/editorial/icons/fact-contact.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/proposal/editorial/icons/fact-duration.svg b/templates/src/main/resources/templates/proposal/editorial/icons/fact-duration.svg new file mode 100644 index 000000000..f435148fc --- /dev/null +++ b/templates/src/main/resources/templates/proposal/editorial/icons/fact-duration.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/proposal/editorial/icons/fact-start.svg b/templates/src/main/resources/templates/proposal/editorial/icons/fact-start.svg new file mode 100644 index 000000000..f82fe3be2 --- /dev/null +++ b/templates/src/main/resources/templates/proposal/editorial/icons/fact-start.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/proposal/editorial/icons/fact-validity.svg b/templates/src/main/resources/templates/proposal/editorial/icons/fact-validity.svg new file mode 100644 index 000000000..75d81c791 --- /dev/null +++ b/templates/src/main/resources/templates/proposal/editorial/icons/fact-validity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/proposal/editorial/icons/goal-check.svg b/templates/src/main/resources/templates/proposal/editorial/icons/goal-check.svg new file mode 100644 index 000000000..159ab3553 --- /dev/null +++ b/templates/src/main/resources/templates/proposal/editorial/icons/goal-check.svg @@ -0,0 +1 @@ + \ No newline at end of file