A proposal editor whose preview and published page can disagree is worse than no editor at all. This one shares the same design code between what a rep sees and what a client signs.

A proposal editor that lets a rep design something the client never actually sees is worse than no editor at all, because it fails exactly when it matters most: after the rep has already told the client to expect it. A real, specific version of this happened with long contract clauses. The editor forced a two-column grid onto a section that could hold a short paragraph or a long one, and the published page had its own separate rule for when text was too long for that layout. The two disagreed. An 875-character clause that looked fine on the rep's screen turned into an unreadable ten-character-wide vertical strip on the page the client actually opened.
A proposal gets drawn in two completely separate places: the editor canvas a rep works in, and the renderer that produces the hosted page and the PDF a client actually receives. Any system that draws the same document twice risks exactly the failure above, two independent implementations of the same idea that quietly drift apart the moment someone changes one without the other.
The fix isn't more testing. It's removing the second implementation. Every color, font, spacing, and layout choice lives in one shared module that both the editor and the renderer read from, so a control that isn't wired into both isn't a smaller feature, it's a decoy that shows a rep something the client will never see. The same discipline applies to the actual content blocks and to how rich text gets cleaned before it's stored. One set of rules, read twice, rather than two sets of rules that happen to agree today.
Building real design flexibility into an existing proposal format is a genuine architectural risk: change the wrong thing and every proposal already sent stops rendering the way it did when it was sent. The six original sections of a proposal, the line items, the cover note, the inclusions, still carry their original structure, because the platform's totals, its PDF generation, and its translation pipeline all depend on reading those exact fields. Nothing about them changed shape. What's new sits alongside them: a freely orderable list of additional content sections, and an optional design theme, both stored as new, optional data next to what already existed. A proposal saved before any of this shipped still renders exactly as it always did.
A hotel group's own theme, colors, typography, a hero photograph treatment, and layout density, can be saved once as the tenant's default, so a rep isn't repicking the brand from scratch on every new proposal. A specific proposal that deliberately wants a different look still wins over that default; the house style only fills in when a proposal doesn't specify its own.

A rep can bold, italicize, underline, link, and list text inline, the small formatting toolbar that follows wherever the cursor is. What that formatted text turns into before it's stored is a real security boundary, not a cosmetic filter, because the output gets baked into a publicly hosted page anyone with the link can open. Only a short allowlist of formatting tags survives. Anything that could actually execute, a script tag, an embedded object, gets dropped along with everything inside it, not just unwrapped. Every attribute on a link gets stripped except the address itself, and that address is checked against a short list of safe schemes, with common tricks for disguising an unsafe one, splitting the word with stray characters, normalized away before the check runs. The sanitizing runs again at the moment the page is actually served, not just when a rep saves an edit, because that second pass is the one that also covers a proposal written by an older version of the editor, or restored from an old saved version, or written directly through the API rather than through the editor's own toolbar at all.
Beyond the six built-in sections, a rep can add from nineteen distinct block types: headings and text, feature rows, an FAQ, a quote, an image paired with text, a full-width image, a photo gallery, an embedded video, a stats row, a table, a timeline, a location block, a call to action, signature lines, and simple layout tools like a divider or a page break. Each one drops in with real placeholder content already in place, so a newly added section is never a blank space a rep has to fill before they can see what it'll look like.
The most telling addition isn't a new block type at all. It's a fourth option in the image picker, alongside browsing an existing photo library, uploading a new one, or linking to an external image: a dynamic image that resolves to whichever hotel the specific deal is actually quoting. The underlying pieces, the data field, the way merge tokens resolve, the safety checks on an external image address, already existed before this shipped. There was simply no button for it, which meant the single most useful choice for a hotel group running one proposal template across dozens of properties was sitting there, built, and unreachable. A capability nobody can actually use isn't really a capability.
An embedded video in a proposal is handled carefully rather than trusted as raw HTML: whatever a rep pastes gets parsed down to just the video's own identifier, then rebuilt into a new, controlled address, so the actual embed can only ever point at one of two known, privacy-respecting video hosts. Anything that can't be parsed that way falls back to a plain poster image that links out instead, rather than either failing silently or opening up to an arbitrary embedded frame.
That same care shows up in how a proposal behaves in print versus on screen. An embedded video plays as a live frame in a browser and would print as a blank rectangle, so the PDF version swaps in a poster image instead. An FAQ that's collapsed into an accordion on screen expands every answer in print, because a collapsed answer in a document nobody can click through is just a missing paragraph. And where a client is required to sign, that signature happens through a proper signature pad running under a security policy scoped to that one page, with the signed image itself validated server-side before it's accepted, never trusted as whatever the browser happened to submit.
A rep's changes save automatically, with a real, honest status indicator, saved, unsaved, currently saving, or failed with an explicit retry, rather than a reassuring message sitting on top of a write that silently didn't happen. Undo and redo cover eighty steps at the level of a whole document change, deliberately staying out of the way of a browser's own text-editing undo while someone's cursor is mid-sentence inside a paragraph.
Version history goes further than most editors bother with: a snapshot is taken automatically before any save that would overwrite meaningful work, again on every publish, and whenever a rep names one deliberately. Restoring an old version is itself never destructive, because the version being replaced gets snapshotted first, which means restoring the wrong one by mistake is just as reversible as the mistake it was meant to fix. A whole finished proposal, its design, its blocks, its content, can also be saved as a reusable template for the next deal that looks similar, so a hotel group's best work doesn't stay locked inside one client's document.

None of this is really about any single feature. It's about a proposal editor where what a rep builds and what a client eventually opens are guaranteed to be the same document, not two documents that happen to agree until the one time they don't. A B2B CRM that hands a rep design freedom without that guarantee is handing them a way to accidentally promise something the client will never actually see.
Twenty minutes, your real properties, no generic demo environment.