Authoring: the section, layout and component reference needed to write proposal content # Proposals > The proposal lifecycle in Pural: draft, share, accept — plus duplicating, versions and what each status means. A proposal is one document for one customer. It starts as a private draft, becomes a shared snapshot the client can open, and ends up accepted, declined or expired. ## Status [Section titled “Status”](#status) The status follows what happens to the proposal rather than being picked from a list. | Status | What it means | | ------------ | -------------------------------------------------------------------- | | **Draft** | Private. Only your team can see it; there is no working public link. | | **Live** | A share link exists and the client can open it. | | **Sent** | The proposal was emailed to at least one recipient. | | **Viewed** | A recipient opened the shared page. | | **Accepted** | A recipient accepted it on the public page. | | **Declined** | A recipient declined it. | | **Expired** | The link was marked expired; recipients see an expired notice. | ## Sharing is a snapshot [Section titled “Sharing is a snapshot”](#sharing-is-a-snapshot) This is the part worth understanding before you send anything. Creating a share link does not publish “the proposal” — it publishes a **frozen version of it**. Recipients keep seeing that version no matter what you change in the editor afterwards, so you can keep working without the document shifting under them. That gives you three actions once something is shared: * **Share new version** — takes a fresh snapshot and makes it the active one for recipients. Do this after you have made the edits you want them to see. * **Back to editing** — withdraws the public version. The current link stops working and the proposal returns to draft. * **Mark as expired** — the link stops working immediately and recipients see an expired notice instead of the proposal. This is for an offer that is genuinely no longer valid, not a way to hide a draft. Previous versions stay listed, so you can tell exactly what a client was looking at when they replied. ## Change history [Section titled “Change history”](#change-history) Separately from what was shared, the editor keeps a history of your own saves. Open **Versions** to see recent ones with how long ago they happened, and **Restore** to go back to one. This is the safety net for a bad edit — not the same thing as the shared snapshots above. ## Duplicating [Section titled “Duplicating”](#duplicating) **Duplicate** copies a proposal, sections and all, as a new draft. It is the quickest way to reuse one specific proposal for a similar client. If you catch yourself duplicating the same proposal repeatedly, that is the signal to make it a [template](/en/library/templates/) instead. ## Deleting [Section titled “Deleting”](#deleting) Deleting a proposal is permanent, and it invalidates any share link that was created from it. # Proposal analytics > Who opened the proposal, how long they stayed, which sections they read and what they clicked. Once a proposal has been shared, **Analytics** in the editor shows how it was actually read. This is the part a PDF attachment cannot tell you. ## What is measured [Section titled “What is measured”](#what-is-measured) | Metric | Meaning | | -------------------- | ------------------------------------------------------------------------- | | **Opens** | How many times the shared page was opened | | **Sessions** | Distinct visits, rather than raw page loads | | **Active time** | Time with the page actually in front of someone, not merely open in a tab | | **Max scroll** | How far down the proposal the reader got | | **Time per section** | Which sections held attention and which were skimmed | | **Last viewed** | When it was last opened | Clicks are tracked by kind: the **accept button**, an **external link**, and a **PDF download**. ## Per recipient [Section titled “Per recipient”](#per-recipient) When a proposal was emailed to several people, the figures break down per recipient — opens, last viewed and active time for each. That is usually the more useful view: it tells you whether the person who actually decides has read it yet. ## Before anything is shared [Section titled “Before anything is shared”](#before-anything-is-shared) Analytics stays empty until the proposal has been shared or sent. There is nothing to measure on a private draft, and the panel says so rather than showing zeros. ## Privacy [Section titled “Privacy”](#privacy) Engagement is measured anonymously and **without cookies**, and only non-bot sessions count — link scanners in mail clients and security tools do not turn into phantom opens. The result is fewer, more honest numbers: an open in Pural is closer to a person than an open in a typical email tracker. # Text, image and button blocks > TextBlock, ImageBlock and ButtonBlock: the three content blocks you place inside a section, and every option each one offers. Three blocks go inside a section’s cells. Everything you write in a proposal is one of them. ## Text (`TextBlock`) [Section titled “Text (TextBlock)”](#text-textblock) The text block is a rich-text editor: headings, paragraphs, bold and italic, lists, links and [placeholders](/en/proposals/placeholders/). Paragraphs come in sizes, which is how you get fine print to look like fine print: | Variant | Use | | ------------------- | -------------------------------------------- | | `t1` | Body copy — the default | | `t2` | Small | | `t3` | Caption-sized | | `small` / `caption` | Muted fine print — but see the caution below | Prefer t1, t2 and t3 `small` and `caption` render, as muted fine print, but the editor’s own type picker cannot produce them or select them again. Anyone who later edits that paragraph loses the variant without being told. Use `t3` for caption-sized text instead. Headings are separate, from level 1 down to level 4, and get their size from the level rather than from a variant — a heading does not take a paragraph variant. Quotes have their own style: a blockquote is what to use for a testimonial or a pulled-out client statement, rather than an italic paragraph. Colour is worth one caution: leave the text colour alone and let [automatic contrast](/en/proposals/sections/#automatic-contrast) adapt it to the background. ## Image (`ImageBlock`) [Section titled “Image (ImageBlock)”](#image-imageblock) | Option | Values | | ---------------------------------- | ----------------------------------------------------------------------------- | | **Source** | An asset you uploaded, or an external URL | | **Alt text** | Describes the image for screen readers and for when it fails to load | | **Fit** (`objectFit`) | `cover` crops to fill, `contain` fits the whole image in, `fill` stretches it | | **Aspect ratio** (`aspectRatio`) | `auto` keeps the original, or force `1:1`, `4:3`, `16:9` or `3:4` | | **Alignment** (`alignment`) | `left`, `center` or `right` | | **Width** (`maxWidthPercent`) | How much of the cell the image fills, `20`–`100` (default `100`) | | **Corner radius** (`borderRadius`) | `none`, `sm`, `md` (default), `lg` or `full` | The two sources are exclusive: either an uploaded asset, or an external URL. A block set to an external URL with no URL filled in falls back to asset mode rather than showing an error. Uploaded images can be cropped and rotated in place, so you rarely need to prepare a file outside Pural first. `cover` with a fixed ratio is the reliable choice when several images sit side by side: without it, images of different proportions make the row look ragged. ## Button (`ButtonBlock`) [Section titled “Button (ButtonBlock)”](#button-buttonblock) A call to action — book a call, open a document, reply. | Option | Values | | ------------------------------------ | -------------------------------------------------- | | **Label** | The text on the button | | **Link type** | A web address, a phone number, or an email address | | **Link target** | The URL, number or address itself | | **Open in a new tab** | For web links | | **Fill** (`backgroundColor`) | Hex colour of the button itself | | **Label colour** (`fontColor`) | Hex colour of the text on it | | **Padding** (`paddingX`, `paddingY`) | Horizontal `sm`–`xl`, vertical `sm`–`lg` | | **Font size** (`fontSize`) | `sm`, `md` or `lg` | | **Corner radius** (`borderRadius`) | `none`, `sm`, `md`, `lg` or `full` | | **Alignment** (`alignment`) | `left`, `center` or `right` | Unlike text, a button’s colours are meant to be set. Automatic contrast does not reach them: a button on a dark section keeps whatever fill and label colour it was given, so check that the label is still legible against the fill you chose. Fill, label colour, padding, font size and corner radius are offered in the editor as a few combined size presets. Setting them independently works and renders, but a combination outside those presets cannot be reproduced by hand afterwards. A phone or email button opens the recipient’s own phone or mail app, which is worth knowing before you use one as the main call to action in a proposal that will mostly be read on a desktop. # The editor > How the proposal editor is laid out: sections, the content canvas, and the tools along the top. The editor has two layers, and keeping them apart makes everything else easier to follow: * **Sections** are the structure — a full-width band of the document with its own background, spacing and column layout. * **Content** is what sits inside a section’s cells — text, images and buttons. You edit the section as a whole through its settings, and the content inside it directly on the canvas. ## Working with sections [Section titled “Working with sections”](#working-with-sections) Sections stack top to bottom in the order the client will read them. You can add a section, reorder them, duplicate one, and delete one. Each section is one of three [kinds](/en/proposals/sections/): a **default** section for free content, a **price** section for the structured pricing table, and an **accept** section for the signature block. The kind is chosen when the section is created and cannot be switched afterwards — a price section holds structured line items, and there is nothing sensible to turn those into if you convert it to free text. ## The toolbar [Section titled “The toolbar”](#the-toolbar) | Action | What it does | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | | **Preview** | Renders the proposal the way the client will see it, without editing controls. | | **Library** | Inserts a [reusable block](/en/library/blocks/) from your library. | | **Resolve placeholders** | Replaces the [placeholders](/en/proposals/placeholders/) in the document with the current customer’s real values. | | **Generate PDF** | Exports the proposal as a [PDF](/en/sending/pdf/). | | **Versions** | The [change history](/en/proposals/#change-history), with restore. | | **Analytics** | How recipients have read the shared proposal. See [Proposal analytics](/en/proposals/analytics/). | | **Edit details** | Title, customer and template metadata, without leaving the editor. | **Undo** and **Redo** cover the last changes on the canvas. ## Saving [Section titled “Saving”](#saving) Changes are saved as you work, and each save adds an entry to the change history. Because a shared proposal is a [frozen snapshot](/en/proposals/#sharing-is-a-snapshot), saving does not change what a recipient currently sees — you have to share a new version for that. # Images in a proposal > Where images come from — uploads, external URLs and stock search — and where in a proposal they belong. An [image block](/en/proposals/blocks/#image-imageblock) and a section [background](/en/proposals/sections/#background-background) both need a picture. There are three places one can come from. ## Where an image comes from [Section titled “Where an image comes from”](#where-an-image-comes-from) | Source | How you get it | | -------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **An upload** (`assetId`) | A file you put in your workspace. Crop and rotate happen in Pural, so you rarely prepare a file elsewhere first. | | **An external URL** (`imageUrl`) | Any absolute URL. Nothing is copied into your workspace — the recipient’s browser loads it from wherever it lives. | | **A built-in background** | The backgrounds Pural ships with, offered in the background picker. | The upload and the URL are exclusive: a block uses one or the other, never both. An external URL is only as reliable as its host Pural does not validate the host of an external URL, and it does not copy the file. If the URL is wrong, or the host takes the image down later, the proposal reaches your client with a broken image and nothing in the editor warns you. Look at the section in preview before sending. ## Stock photography [Section titled “Stock photography”](#stock-photography) An [AI assistant](/en/ai/authoring/) can search stock photography and place a result directly, which is the practical way to get a proposal illustrated without hunting for files yourself. It sees the actual pictures rather than filenames, so it can pick one that suits the section. Two things worth knowing: * The hourly search quota is shared across everyone in the workspace, so an assistant is told to search once per section and reuse what it found. * Results that carry a stricter licence are filtered out before you ever see them. If stock search is unavailable — no quota left, or not configured — an assistant is instructed to continue without an image rather than invent a URL. ## Where images belong [Section titled “Where images belong”](#where-images-belong) An image earns its place or it is decoration. A useful rule of thumb, and the one the guided prompt follows: | Section | Images | | ----------------------- | -------------------------------------------------------- | | Cover | One, as a full-height background with a legibility layer | | Team, testimonials | One per person | | Features, benefits | One per item | | Introduction, summary | One or two | | Pricing, scope, closing | **None** | A photo behind a full-height cover does more for a proposal than the same photo squeezed into a column. And a proposal that is nothing but text reads as a memo — the opposite failure is just as real. ## Images as a background [Section titled “Images as a background”](#images-as-a-background) A background image switches automatic contrast off, which is the one thing to remember about them. Text no longer adapts to what is behind it, so pair every background image with a legibility layer — `imageOpacity`, an overlay, or `contentFill`. See [Image backgrounds and legibility](/en/proposals/sections/#image-backgrounds-and-legibility-contentfill). ## Cropping surprises [Section titled “Cropping surprises”](#cropping-surprises) `objectFit: "cover"` with a fixed aspect ratio crops to fill. That is what you want for a row of images that should look even — and it is also how a portrait ends up cropped through someone’s head at `1:1`. A settings list cannot show you that. The preview can. # Rows and columns > Splitting a section into columns, setting relative column widths, and the limits that apply. Inside a section, content sits in **rows**. A row is split into **cells**, and each cell holds its own stack of blocks. That is how you get a picture beside a paragraph instead of under it. ## Columns [Section titled “Columns”](#columns) A row can hold up to **four** cells. Beyond that a proposal column is too narrow to read on a phone, where every column collapses to full width anyway. ## Relative widths [Section titled “Relative widths”](#relative-widths) By default the cells in a row share the space equally. Widths let you weight them instead — they are ratios, not pixels or percentages: | Widths | Result | | ----------- | ------------------------------- | | `[1, 1]` | Two equal columns | | `[1, 2]` | A third and two thirds | | `[2, 1]` | Two thirds and a third | | `[1, 1, 2]` | A quarter, a quarter and a half | The list has to have exactly as many entries as the row has cells. A `[1, 2]` on a three-cell row does not partly apply — it is discarded, and the row renders as equal columns. ## Nesting [Section titled “Nesting”](#nesting) A cell can contain its own rows, one level deep. That covers the realistic case — a two-column split where one side is itself stacked — without letting a proposal turn into a grid nobody can maintain. Rows nested deeper than one level are dropped. ## On small screens [Section titled “On small screens”](#on-small-screens) Columns collapse to full width and stack in reading order: left to right, then top to bottom. Check a multi-column section in [preview](/en/proposals/editor/) before sending — a caption placed to the right of an image ends up underneath it on a phone, which is usually fine, but occasionally reads wrong. # Placeholders > Insert customer and company values that fill themselves in, instead of retyping them in every proposal. A placeholder is a marker you drop into text that stands for a value Pural knows — the customer’s company, the contact’s name, your own organization details. It is what makes a [template](/en/library/templates/) reusable: write “Dear «contact name»” once and every proposal built from it addresses the right person. ## Inserting one [Section titled “Inserting one”](#inserting-one) In a [text block](/en/proposals/blocks/#text), start a placeholder from the editor’s insert menu and pick the value you want. It appears in the text as a single highlighted token, not as loose characters — you cannot accidentally break one by editing half of it. ## How they resolve [Section titled “How they resolve”](#how-they-resolve) Placeholders fill in from the **customer attached to the proposal**, plus the proposal itself and your organization. They are resolved every time the proposal is displayed — in the editor, on the public page, in the PDF — so attaching a different customer updates every placeholder at once. Nothing is stored as text and nothing has to be re-saved. Where a value is missing — no customer attached yet, an empty field — the placeholder falls back to showing its own name in braces, `{{customer.name}}`. That is the signal that there is nothing to fill in from yet, not a broken placeholder. **Resolve placeholders** in the editor toolbar switches between the two views: the real values, and the placeholder names. Use the first to read the proposal exactly as the client will, and the second to see at a glance which parts are placeholders at all. ## In a template, and in a proposal [Section titled “In a template, and in a proposal”](#in-a-template-and-in-a-proposal) The same placeholder means something different depending on where it sits: * In a [template](/en/library/templates/) it is the whole point. There is no customer, so the template shows `{{customer.name}}` — that is the template being correct, not unfinished. * In a proposal it should be filled. A placeholder still showing its braces in a proposal you are about to send means the value behind it is missing. Typing a placeholder by hand does not work Placeholders are editor objects, not text patterns. Typing something like `{{customer.name}}` into a paragraph produces exactly that string — Pural has no reason to treat it as special, and the client receives the braces verbatim. Always insert placeholders from the menu. An [AI assistant](/en/ai/authoring/) over MCP *can* insert real placeholders, because it copies the exact markup from the workspace rather than typing the token. The check is the same either way: if you see braces in a proposal with a customer attached, look at whether that is a placeholder with a missing value or a piece of text somebody typed. # Pricing and acceptance > The price table and the acceptance block: the two sections that turn a document into an offer a client can say yes to. Two section kinds exist because two parts of a proposal are not free text: what it costs, and how the client agrees to it. ## The price section [Section titled “The price section”](#the-price-section) A price section holds line items in a structured table rather than as typed-out text. Each line has its description, quantity and price, and the totals are calculated. That is the whole reason it is not a text block: a typed total goes stale the moment someone edits a line above it. You can give the table a description — the framing sentence above the numbers — and there can be more than one price section in a proposal when you want to separate, say, one-off setup from a monthly fee. ### Optional and selectable items [Section titled “Optional and selectable items”](#optional-and-selectable-items) Line items can be offered as choices rather than as fixed scope, so the client picks what they want on the public page and the total updates with their selection. Quantities can be adjustable in the same way. Use this instead of sending three separate proposals for three package sizes. ## The accept section [Section titled “The accept section”](#the-accept-section) The accept section is what turns a document into an offer: it renders the acceptance controls on the [public page](/en/sending/public-page/), where the recipient can accept — signing by drawing a signature where that is configured — or decline. Put it last. It is the end of the argument, and it reads as an interruption anywhere else. Accepting sets the proposal to **Accepted** and declining to **Declined**, both visible in your proposal list without anyone having to email you about it. # Sections > The three section kinds and every setting that controls how a section looks: width, padding, rowGap, columnGap, minHeight, verticalAlign, background and contentFill. A section is one full-width band of the proposal. It owns the background, the spacing and the column layout; the text, images and buttons live inside its cells. ## The three kinds [Section titled “The three kinds”](#the-three-kinds) | Kind | What it is for | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | **Default** | Free content — text, images, buttons, in any column layout. Most sections are this. | | **Price** | The structured pricing table. Line items, quantities and totals, calculated rather than typed. See [Pricing and acceptance](/en/proposals/pricing/). | | **Accept** | The signature and acceptance block the client uses to say yes. Usually the last section. | The kind is fixed when the section is created. A price section stores structured line items and an accept section stores a signature configuration, and neither has a sensible free-text equivalent to convert into. ## Settings [Section titled “Settings”](#settings) Every setting below is optional, and leaving one out is not the same as it having no effect — it falls back to the default in the table. That matters when a single section looks subtly different from its neighbours: usually the setting was never set on that one section rather than deliberately changed. ### Width (`width`) [Section titled “Width (width)”](#width-width) How wide the content is allowed to grow, independent of the section’s own full-width background. | Value | Result | | ----- | ----------------------------------- | | `s` | Narrow — comfortable for long prose | | `m` | Medium | | `l` | Wide (default) | ### Padding (`padding`) [Section titled “Padding (padding)”](#padding-padding) The vertical and horizontal breathing room inside the section: `xs`, `s`, `m`, `lg` (default), `xl`, `2xl`. Larger values read as more deliberate and more expensive; they are also what makes a cover section feel like a cover. ### Row and column gaps (`rowGap`, `columnGap`) [Section titled “Row and column gaps (rowGap, columnGap)”](#row-and-column-gaps-rowgap-columngap) The space between stacked rows and between side-by-side columns: `xs`, `sm`, `md` (default), `lg`, `xl`. They are set separately, so you can keep columns tight while rows stay airy. ### Minimum height (`minHeight`) [Section titled “Minimum height (minHeight)”](#minimum-height-minheight) Forces the section to occupy at least part of the screen, regardless of how little content it holds: `none` (default), `1/3`, `1/2`, or `full` for a full-viewport section. This is how you build a cover that fills the screen. ### Vertical alignment (`verticalAlign`) [Section titled “Vertical alignment (verticalAlign)”](#vertical-alignment-verticalalign) Where the content sits when the section is taller than its content: `start` (default), `center` or `end`. It only has a visible effect together with a minimum height. ### Background (`background`) [Section titled “Background (background)”](#background-background) Either a solid colour, or an image with: * **size** — `cover`, `contain` or `auto` * **position** — `top`, `center` or `bottom` * **image opacity**, plus an **overlay colour and opacity** for darkening a photo enough that text stays readable on top of it ### Automatic contrast [Section titled “Automatic contrast”](#automatic-contrast) Automatic contrast is not a setting you turn on. It always applies: Pural measures the luminance of the section background and picks the text colour itself, keeping the contrast at WCAG 4.5:1. That is why you can choose any background colour you like and the text stays readable. There is no `autoContrast` setting and no way to switch it off — writing one has no effect. Caution Do not hard-code a text colour to compensate for a dark background. You end up fighting the contrast resolver, and the result can be text that is invisible on one background and fine on another. The one exception is an **image background**, where automatic contrast does not apply — see below. ### Image backgrounds and legibility (`contentFill`) [Section titled “Image backgrounds and legibility (contentFill)”](#image-backgrounds-and-legibility-contentfill) A `type: "image"` background switches automatic contrast off. Nothing adapts the text to what is behind it, so a dark headline over a dark photo ships exactly as written, and the settings look perfectly correct while it does. Always pair an image background with a legibility layer. Three of them, weakest to strongest: | Setting | What it does | | --------------------------------- | ----------------------------------------------- | | `imageOpacity` | Fades the image toward the section’s own colour | | `overlayColor` + `overlayOpacity` | Lays a tint over the whole image | | `contentFill` | Puts a solid panel behind the content only | `contentFill` takes a colour, an opacity, a blur, a corner radius and an inset, so it can be anything from a barely-there frosted panel to a solid card. It is the reliable choice for a full-height cover with a headline on a busy photo. An individual cell can carry its own `fill` with the same shape. It is suppressed when the section already sets `contentFill`, so the two never stack. ## Keep settings consistent [Section titled “Keep settings consistent”](#keep-settings-consistent) A proposal reads as one document when its sections agree. If every section uses `lg` padding and width `l` and one uses `m` and `s`, that section looks like a mistake even if nobody can say why. Vary the background deliberately — that is what separates a cover or a callout from body sections — and keep the structural settings the same unless you have a reason.