A major-third scale from a 15 px base
+657.2 pxCheckout
+545.8 pxPay now
+436.6 pxTotal incl. VAT
+329.3 pxBuying as
+223.4 pxSupplier instructions
+118.8 pxWeb and social media
015 pxPrices in NOK, including VAT.
−112 pxPhoto: creator / credit
One job per signal
| Signal | Looks like | Used only for |
|---|---|---|
| Bold | Pay now | Names of buttons and fields |
| Italic | faktaboks, Pressens hus | Foreign words and titles |
| Highlight | incl. VAT for everyone | What changed since last time |
| Small caps | NTB · VAT · PDF | Abbreviations in running text |
| Underline | a link | Links, nothing else |
| Colour | Decided / Assumed | Status, never decoration |
| Mono |
-lib/vat.ts
|
Code, paths, IDs |
| Caps, tracked | Checkout | Eyebrows above a heading |
A docs page with every level named
The badge word at nine weights
Numbers that line up, and numbers that read
Proportional
- 1 111 kr
- 4 448 kr
- 11 111 kr
- 8 880 kr
Tabular
- 1 111 kr
- 4 448 kr
- 11 111 kr
- 8 880 kr
Lining, serif
- 8 Oct 2026
Old-style, serif
- 8 Oct 2026
About 62 characters to a line
Experiments often test ideas that contradict each other, so each one is sealed off. Each folder may import only itself and the shared platform. Reusing another experiment's code means copying it. A commit with a cross-import is refused.
A commit with a cross-import is refused before it reaches the repository.
Three levels, each stepped in
Buyer type comes from the active workspace. No company/private choice in checkout.
Company name, org. no., address, and "Ordered by".
"Pay now" places the order straight away.
Let the marks hang outside the edge
Set flush
“A feature must work on its own.”
- Seller and buyer
- VAT breakdown
Hung
“A feature must work on its own.”
- Seller and buyer
- VAT breakdown
The small characters that make a price look Norwegian
| Wrong | Right | Why |
|---|---|---|
| kr 1,711.00 | 1 711 kr | D2: space as thousands separator, øre only when there are any. The spaces are non-breaking, so a price never splits over two lines. |
| 25% | 25 % | nb-NO puts a space before the per cent sign (D1, D3: "VAT (25 %)"). |
| Pay now - 5 475 kr | Pay now · 5 475 kr | D8 writes the button with a middle dot. |
| -25 kr | −25 kr | A minus sign is as wide as a plus; a hyphen is not. |
| 2-3 days | 2–3 days | An en dash for ranges. |
| 1920x1080 | 1920 × 1080 | A multiplication sign for resolution and print size (D16). |
| "Included" | “Included” | Curly quotes in text; straight ones belong in code. |
The news stack
Companies now see prices with VAT, just like everyone else
One answer from UX on 8 October replaced the design's split between company and private buyers. Every price on the site now says "incl. VAT".
Who wrote it, where, and what changed since
Oslo (NTB): The receipt moved out of Baseline and became a feature of its own, with its own sample orders, so it works without any prototype.
Three lines deep, with a small-caps lead-in
There's no design for the receipt, so it follows the letter in NTB's brand guide: logo top left, the seller's addresses in a narrow left column, buyer and date at the top, set in Geist with Lava and Dyp mørkerød.
The capital stands on the first line
Baseline is the "before" the product admin prototype is compared with, finding by finding. The admin copies the one used in the user test, quirks included, so the two can be compared.
Four facts before the first sentence
Before, the design split buyers: companies without VAT, private buyers with. Admin base prices are still entered excluding VAT.
Silos, in four lines
- One experiment per session.
- Code imports only its own experiment and src/platform.
- Reuse by copying, with a note of the source commit.
- Fallow refuses a commit with a cross-import.
The newspaper sidebar of facts
Facts The receipt
- Format
- A4 PDF printed by headless Chrome from the receipt page
- Seller
- NTB AS, Skippergata 24 (Pressens hus), 0154 Oslo
- Colours
- Lava, Dyp mørkerød and warm greys, whatever the theme
- Status
- "Paid"; payment method is not modelled
Four figures worth remembering
A sentence that leads with its figures
Of the 232 images in the fixtures, 200 are editorial. A base price of 1 711 kr plus 25 % VAT gives 2 138,75 kr, and because the designs only show whole kroner, the customer sees 2 139 kr.
Three marker colours, three meanings
Show "Photo: creator / credit" per image with a help tooltip. Whether it depends on editorial vs commercial use stays an open question in the checkout chart. Still waiting for an answer from Elisabeth.
Press a key to isolate one kind of phrase
Write "incl. VAT" next to every customer price. Under price lists: "Prices in NOK, including VAT." Checkout, confirmation and receipt totals, for every buyer: "Subtotal excl. VAT", "VAT (25 %)", "Total incl. VAT".
A reviewer's pen on a rule
One checkbox for the license agreement; mention "the supplier instructions listed for the images" only when an image in the order has instructions. Private buyers tick a separate withdrawal waiver.
A rule, rewritten, with the reason beside it
Marks in the text, instructions in the margin
The checkout prototype says licence1 and Web & Social2; a plan badge says Subscribed3. Prices read kr 1,711.004 on the5 site.
- 1license (US)
- 2Web and social media
- 3Included
- 41 711 kr
- 5insert: live
Tap a dotted word
Each experiment is a . Business rules start from the , the docs sit in a , and keeps it that way. Each session ends with a .
TanStack's file names, defined
- route.tsx
- The route for its folder's own URL, usually a layoutNames a section: its title is the breadcrumb
- index.tsx
- The page at the folder's URL exactlyEvery breadcrumb opens a page
- $name
- A URL parameterMarkdown docs, rule charts, orders
- _name
- A pathless layout_docs wraps docs pages in the docs shell
- -name
- Ignored by the router-lib for code, -docs for markdown
- a.b.tsx
- Flat nesting: b under aOnly for a page plus its PDF
Small caps, spelled out on tap
VAT is shown on every price. The receipt is an A4 PDF with NTB's addresses and a placeholder org. no. Prices come from the admin, entered in NOK excluding VAT, then formatted as nb-NO.
Tap an abbreviation to expand it in place; tap again to fold it.
A translation floating above the word
Set in Geist with Lava and Dyp mørkerød, from Pressens hus, Skippergata 24.
Norwegian copy, word by word
One line lifted out of the column
A prototype in a user test shows only what its users would see.
docs/routing.mdApp pages never show in the docs nav or breadcrumbs, and their tab titles name only the app. An app may build its own breadcrumb from its own routes.
The facilitator's controls are behind the flask icon, the prototype menu, so a participant never sees a switch they aren't meant to touch.
The source, named and linked
A receipt must show what was bought and paid, even if prices or the cart change later.
Numbered notes beside the line they belong to
The PDF route has headless Chrome load the receipt page from this server's own localhost address1Not the address the request came in on. See receipt/-lib/pdf.server.ts., so the receipt also works when the prototype is shared through a tunnel2Through ngrok, Chrome got the tunnel's warning page instead of the receipt. That is why R5 exists.. One React component is the on-screen receipt, the browser print and the PDF, with sizes in millimetres and points3R4: "One thing to design and check.".
A rule read by its parts
- Says
- An image's own instructions from the supplier are shown where they apply, nothing more.
- Rule
- One alert per image headed "Supplier instructions", only when it has any.
- Why
- NTB's search API has one free-text field.
- Status
- Ferdinand's proposal; an assumption until confirmed.
Details at the bottom, one tap away
The single-purchase flow lives on the order system board1. Checkout isn't made for phones in this round2, and there is no payment step yet3.
Five callouts, five levels of urgency
A note that tells you what to do next
This rule is still an assumption
Supplier instructions (D17) are Ferdinand's proposal. Until confirmed, treat them as provisional.
Next, on the wall
A side story the text flows around
The public site has search, an image's page with the purchase panel, the mini cart, the cart, checkout for companies and private buyers, and the confirmation with a receipt you can open as a PDF. The purchase panel appears in every situation from the designs: no plan, a pack, a subscription, both, or an image the plan doesn't cover.
Checkout is as UX designed it for LIP-1440, updated with Ferdinand's answers: prices with VAT for everyone, a review of each image, one box to accept the terms, invoice details for companies, and help that opens in place. The admin is as it was in the user test on 30 September.
Three participants, three reactions
I like that it says incl. VAT right next to the price. I don't have to ask finance what we actually pay.
"Buying as" is clear, but I wanted to change it right there. I didn't expect to go to workspace settings.
The dark picture next to the white panel felt like two different websites glued together.
One quote, given the whole stage
“The terms opened right there in checkout. I never lost my place.”P2 · Archive manager
Short quotes, sorted into piles
Prices 2 of 4 shown
Whole kroner, good.P1
Is VAT in the total or on top?P4
Terms 2 of 3 shown
One box to tick is enough.P6
What's a withdrawal waiver?P7
Help 1 of 2 shown
I'd just phone them.P3
Timestamps, speakers, and the line that mattered
A question asked and answered
+1 · 3
People as chips inside a sentence
Credit lines wait on EElisabeth; supplier instructions and the terms links on FFerdinand. Prices on the public site come from the admin set up by #product-config.
Reusing another experiment's file
-
Find the file you needFor example the receipt component in the receipt feature.
-
Copy it, don't import it
bun scripts/copy-from.ts receipt prototypes/baseline receipt.tsx -
Find it under -lib/from-receipt/With everything it needs, and the source commit in copied-from.json.
-
Change it freelyYour experiment owns its copy now.
Where checkout is, and what doesn't exist yet
- Cart
- Checkout
- Payment
- Confirmation
- Receipt
Four ways to say "how far along"
Before every commit
Done, waiting, not started
- Checkout as designed for LIP-1440Done
- Receipt you can open as a PDFDone
- Contact us in the purchase panelTo align
- Logged-out visitors (LIP-1546)Undecided
- Order history and plan pagesNot yet
Two weeks of the prototype
-
User test of the adminBaseline later mirrors it, quirks included.
-
Header and widths follow the live siteD9, D12
-
Receipt becomes a featureD27–D29 move out as R1–R6
-
UX answers seven questionsVAT for everyone, one checkbox, terms in place D5D15D22
-
Silos and boundariesExperiments sealed; reuse by copying
Baseline's decisions, by group
-
Prices and words 10
D1Norwegian formattingD5Prices incl. VAT for allD23"license", US spelling
-
Pages and layout 6
D24All light or all darkD25Starts on Editorial
-
Checkout 14
D8Pay button always worksD14No payment step yetD31Not for phones yet
Eight bullets, eight tones of voice
Arrow · consequence
- Remove the last image
- Empty cart
En dash · plain
- Creative
- Editorial
Tick · allowed
- Copy with copy-from.ts
- Import src/platform
Cross · not allowed
- Import another experiment
- Import src/reference
Squared numbers · order
- Cart
- Checkout
Letters · options
- No plan
- A pack
Roman · formal parts
- Seller
- Buyer
Diamond · highlights
- Five customers
- Admin as tested
Hanging decimal numbers for terms
License terms · Web and social media
-
Use
- The image may be published once on the buyer's own website and social media accounts.
- Print use is not included.
-
Credit
- Every use shows the credit line "Photo: creator / credit".
- Supplier instructions for the image take precedence over these terms.
When can a buyer pay?
canPay guard in Baseline's checkout machine
(rules/checkout.ts), with D8 for the error.
Prices and badges, right and wrong
Company buyer and private buyer in checkout
Company
- Buying as
- Company, org. no., address, and "Ordered by"
- Checkboxes
- One: the license agreement
- Invoice details
- Your reference, PO number (optional)
- Prices
- Incl. VAT
Private
- Buying as
- Name, address, email
- Checkboxes
- Two: agreement and withdrawal waiver
- Invoice details
- None
- Prices
- Incl. VAT
One total, before and after D5
What changed in a decision's wording
Widths max 1200 px everywhere
follow the live site:
full-width header and search, readable content columns.
Content gets a max width for reading; backgrounds may run full width.
Copying code between experiments
+For
- Each experiment owns its versionstrong
- Ideas can contradict freelystrong
- Source commit is noted
−Against
- Fixes don't spread by themselvesstrong
- Duplicated code
VerdictCopy. Duplication is reported by bun run check, but doesn't stop anything.
The same license, priced the new way
Three things people still believe
Companies see prices without VAT.
Since 8 October everyone sees prices incl. VAT (D5).
The buyer picks company or private in checkout.
It comes from the active workspace (D13).
You can change the license in checkout.
Only in the cart; checkout can only remove (D18).
Before and the thing it's compared with
Baseline
The "before"- Admin as in the 30 Sep user test
- Quirks kept, bugs not
- Labels as tested
Product admin
The prototype- Compared finding by finding
- Its own decisions
- Its own silo
One badge family, five weights
Solid · strongest
PaidRefusedPrototypeSoft · in lists
IncludedEditorialCreativeOutline, pill, dot
DecidedAssumedOpenTiny caps · beside a title
NewDraftTo alignSplit · key and value
VAT25 %buyercompanystatusPaidChoose a family, then narrow it
Showing 62 of 200 editorial images
Live, waiting, stopped, never started
How many, at a glance
Press "Add an image": the badge counts up and pops once.
The facilitator's shortcut
Open the prototype menu with Alt+Shift+P, or ⌥⇧P on a Mac. It works over modals too. Close it with Esc.
Where a fact comes from, coloured by system
Prices incl. VAT D5 came from JiraLIP-1440, and the receipt follows suit R7. The flow is drawn on Figma381:7458; the admin is copied from im-web906f196.
How sure we are, said inline
Everyone sees prices with VAT Decided. Supplier instructions show only when present Assumed. Whether the credit line depends on editorial or commercial use Open.
Real or made up, marked on every card
"Prices in NOK, including VAT."quoted said P3, a picture editor.invented
Pictograms set at the size of the words
Open the prototype menu to switch customer. In checkout, the License agreement opens in a new tab and Contact us shows phone and email.
A line that says what comes next
Breaks without a heading
Eleven rules, labelled
A price list the eye can follow across
- Web and social media2 139 kr
- Included in your plan0 kr
- Editorial, print and web3 125 kr
- Commercial, one campaign11 875 kr
- Pack of 10 editorial downloads18 750 kr
Ten frames, ten levels of separation
Words inside forms
not
imported
The receipt's status, stamped
Receipt · Order 2026-1008-03
A sash across a corner
Checkout
Not made for phones in this round. Pay now places the order straight away.
The paragraph bends round the figure
Totals from prices that include VAT are the same for companies and private persons: VAT is the part inside, the subtotal excl. VAT is what's left. A net price with VAT added is rounded to whole kroner. Every buyer, company or private, sees amounts including VAT and the same VAT breakdown, and the receipt shows it as "Subtotal excl. VAT", "VAT (25 %)" and "Total incl. VAT".
Columns with rules, a headline across them
Experiments are sealed off from each other
Experiments often test ideas that contradict each other, so each one is sealed off. Each folder may import only itself and the shared platform.
Reusing another experiment's code means copying it. A script copies a file and everything it needs into a folder named after its source, and notes the source commit.
The working model is the source. It lives in the reference folder. Baseline has its own copy; improving the shared model means changing the reference, then copying it again.
Fallow checks it. Every folder under prototypes and features is its own zone automatically, after each edit and in the commit hook.
A bracket that groups lines and names them
A path coloured by what each part means
The shape of an experiment
baseline/
├─ route.tsxnames the experiment
├─ _docs/docs shell, adds nothing to the URL
│ ├─ index.tsxthe docs start page
│ └─ decisions.tsxfrom -lib/decisions.ts
├─ app/the running prototype, own chrome
│ └─ _public/…/prototypes/baseline/app/search
├─ -lib/code: components, rules, decisions
└─ -docs/markdown for people
The VAT arithmetic, explained line by line
export const VAT_RATE = 0.251 export function withVat(net: number): number { return Math.round(net * (1 + VAT_RATE))2} export function priceSummary(prices: number[]) { const total = prices.reduce((a, b) => a + b, 0)3 const vat = Math.round(total - total / (1 + VAT_RATE))4 return { subtotal: total - vat, vat, total }5}
- 1Norwegian VAT on image licenses: 25 %.
- 2A net price with VAT added, rounded to whole kroner (D11). 1 711 becomes 2 139.
- 3Start from prices that already include VAT, the same for companies and private persons (R7).
- 4VAT is the part inside the total, not added on top.
- 5The subtotal excl. VAT is what's left, so the three lines always add up.
A command, its output, and the refusal
~/im-web-prototypesbun scripts/copy-from.ts receipt prototypes/baseline vat.ts ✓ copied vat.ts → -lib/from-receipt/ ✓ noted source commit in copied-from.json ~/im-web-prototypesgit commit -m "Use the receipt's VAT" ✗ fallow: baseline imports features/receipt copy it instead: bun scripts/copy-from.ts ~/im-web-prototypes
Four kinds of computer text in one sentence
Every route sets staticData with a title;
layouts that aren't a step use title: null. The
type guard lives in
src/platform/
codeidentifiersvaluea literal valuepatha file or foldercmdsomething to type
What each part of an address means
Without /app the same prefix is the docs: /prototypes/baseline is the docs start page, inside the pathless _docs layout.
The import that's refused, and the fix
Three breadcrumb styles, one source
Chevron
Pills
Slash, collapsed
Tab title, built backwards
Same checkout, three viewpoints
- "Buying as": company, org. no., address
- "Ordered by": the user's name and email
- Optional invoice details: your reference, PO number
- Name, address and email
- A separate withdrawal waiver to tick
- Same prices, incl. VAT
- A copy of the order, kept when it's placed (R3)
- Seller, buyer and "Attn."
- VAT breakdown and license terms per license
Questions a participant might ask
Why can't I change the license in checkout?
Why is there no payment step?
Where do I choose company or private?
A decision as a card: ID, headline, rule, source
A page is all light or all dark, never a dark column next to a light panel.
The mix of dark and light on the details page drew negative feedback.
Each image in checkout is a card with everything you need to check before paying.
Thumbnail at true aspect ratio, title (two lines max), ID, price, license, credit.
The receipt has its own sample orders and works without any prototype.
A feature must work on its own, and prototypes may change their sample data freely.
The headline on the front, the reason on the back
The credit line's little question mark
Hover, focus or tap the question mark.
A message that slides in, then leaves
Nothing here yet, and where to go
Press Pay now without ticking
Two lines in the card, one in the summary
Supporters celebrate on the square outside the town hall after the final whistle in the cup final, with flares and flags in the club colours
ID NTB-8XK2 · 2 139 kr incl. VATSupporters celebrate on the square outside the town hall after the final whistle in the cup final, with flares and flags in the club colours
Hover for the full title; tap to openGuess the decision, then check
The end of a docs page
Where you are inside one page
On this page
In short The shape of an experiment TanStack's file names Our conventions, and why Silos: what an experiment may use One source: staticData What catches mistakesA dismissible line across the top
The same decision, said three ways
Change the words, and the numbers follow
A buyer licensing images at a base price of pays 6 417 kr in total, of which 1 283 kr is VAT, and ticks one box before paying.
Computed with the receipt's own rules: withVat() rounds each price to whole kroner, priceSummary() finds the VAT inside the total (vat.ts). The checkbox count follows D15. 1 711 kr is D11's example; the other base prices are invented.
Colour running through the letters
Pattern inside, line around, block behind
A slogan running round a seal
The words run along an SVG circle with textPath, stretched to close the loop exactly. In the middle, the one folder every experiment may import.
A spine down the side
Not there yet
Visitors who aren't logged in. What they should see isn't decided.
Order history and plan pages. Approval steps for editorial use and for some suppliers. A designed front page.
Real interface strings, typed out
Decisions crawling past, like a news wire
Every line set to the full width
Where a printed page says where you are
License terms
Web and social media. The image may be published once on the buyer's own website and social media accounts.
Supplier instructions. Only when an image has them.
Credit. Every use shows "Photo: creator / credit".
Editorial, print and web
Use. One publication in print and on the web within 30 days.
Not included. Advertising and commercial use.
The receipt, set like NTB's letter
SellerNTB AS
Skippergata 24 (Pressens hus)
0154
Oslo
PostBoks 6817 St. Olavs plass
N-0130 Oslo
Org. no.000 000 000