# Flux 2.3.0 — deck contract For building Kaptio slide decks. This file is complete: the premise, the rules that differ from product UI, the pacing, and the markup for every layout. This is NOT the product contract. If you are building an interface, stop and read https://flux.kaptio.com/llms.txt instead. The two disagree deliberately — a slide relaxes rules that a dashboard cannot, and applying deck rules to product UI is a defect. Reference: https://flux.kaptio.com/patterns/decks/ Example deck: https://flux.kaptio.com/decks/example/ PREMISE ======= A slide is not a small web page. It is read in seconds, from the back of a room, while somebody talks over it. The rules that keep a dense operational interface legible — one ground, restrained colour, a bounded type scale, no decoration — are the same rules that make a deck boring, because they are tuned for a surface nobody is looking up at. So the deck layer relaxes the rules that only make sense at desk distance, and holds every rule that carries the brand. What loosens is scale, ground, asymmetry and bleed. What never loosens is tokens, Lexend at two weights, JetBrains Mono as the second voice, and contrast. SETUP ===== A deck is a standalone HTML document. Two stylesheets, one script, one wrapper, one section per slide. Never load flux-deck.css into product UI: it derives the root font size from the viewport so the canvas scales as one piece, and that must not reach an app. Deck title
The composition is 80 x 45rem — 16:9, and 1280 x 720 at a 16px root. Leftover viewport takes the current slide’s ground, so a dark slide is not framed by a light page. Themes: set data-flux-theme="light" | "dark" | "deep" per slide, not just on the root. Forest: add data-ground="forest" to a deep slide for a section or statement beat. No other grounds exist. Slides advance to the RIGHT. flux-deck.js draws previous and next arrows, adds click-to-advance (click the left quarter to go back) plus the arrow keys, space, Page Up/Down and Home/End. Snapping is CSS, so a swipe, a trackpad and a presenter remote work even if the script never loads — include it anyway. Do not write your own navigation, and do not add slide numbers, dots or a progress bar: they are chrome the room did not ask for. WHAT LOOSENS ============ Each product rule, and what replaces it on a slide. - Product: The type scale stops at --flux-text-6xl. Deck: Decks add --flux-display-sm through --flux-display-xl. These are deck-only: a display size in product UI is a defect, not a bold heading. - Product: A view has one ground. Deck: Every slide sets its own data-flux-theme. A deep teal statement between two light slides is the cheapest visual event in the system, and contrast is already audited for all three themes. One extra ground exists for decks only: forest, set with data-ground="forest" on a deep slide. - Product: Teal carries the system; other hues appear only when they carry meaning. Deck: A slide may take any product accent with data-accent. On a slide the accent is identity rather than status, so it needs no meaning — but it stays graphic. - Product: One yellow CTA element per view. Deck: Yellow is not a slide ground. The closing ask uses a full-bleed photograph or muted background video under a deep-teal overlay. - Product: No centred body copy. Deck: Statement and quote slides centre. There is no body copy on them to centre. - Product: No three-column grid of icon, heading and paragraph as a default layout. Deck: The grid slide is exactly that, and it is right here — a taxonomy held on screen for twenty seconds is not a landing page. - Product: Constrain reading columns to --flux-measure-prose. Deck: Slides bleed to the edge. Images fill the canvas, and marks are cropped by it deliberately. - Product: Never exceed --flux-duration-slow. Deck: Content settles on arrival using a scroll-driven timeline, so it tracks the presenter rather than a clock. Still opacity and transform only. - Product: No decorative marks, bars or dots. Deck: A slide may carry one oversized typographic mark, or one hairline dot field. One. Two is decoration, and a coloured bar on the edge of anything is still banned. WHAT HOLDS ========== Unchanged from product UI. A slide is not an exemption. - Every value comes from a token. No raw hex, no raw dimension, no Tailwind arbitrary value. - Lexend at 300 or 700. JetBrains Mono at 400, 500 or 700. Never a third family. - Never load flux-prototype.css in a deck. Google Sans Flex and Manrope belong to product prototypes; a deck always sets in Lexend and JetBrains Mono. - Load flux.css and flux-deck.css from the Flux CDN, exactly as in the setup. Never copy token values into the deck, never redefine --flux-* variables, and never write var(--flux-…, #fallback): a deck that still renders without flux.css is a private copy of Flux that no theme or update reaches. - Do not load fonts yourself. flux.css loads Lexend at 300 and 700 and JetBrains Mono; a font link that adds Lexend 400, 500 or 600 is a defect. - Grounds are light, dark and deep, plus forest (data-ground="forest" on a deep slide). Contrast is WCAG 2.2 AA at minimum (4.5:1 text, 3:1 non-text) and stays audited. Never a hand-picked colour, never a ground set with style or a data-*-bg hex. - A story, a chapter or a persona never gets its own hue. Tell people apart with the avatar, the name and the role, and chapters apart with the title and the ground rotation. Status colours — green, yellow, blue, orange — mean status, not identity. - Product accents colour type and data: the oversized mark, the list numerals, chart bars, a donut arc. Never decoration — no bar on the edge of a card, no rule beside a label — and never a word you are meant to read. - Interface radius stays --flux-radius-sm. A slide is not a reason for a soft corner. - No gradient fills, no glassmorphism, no glow, no neon, no blur behind content, no gradient mesh. - No emoji as an icon system. - Animate opacity and transform. Never width, height, top, left, margin or padding. - Deck videos are decorative and muted. They pause off-slide, respect reduced motion, and always have the Flux pause control. Background video with the deep-teal overlay is allowed on the cover and the closing ask; the agenda keeps its own video-backed layout. Nowhere else. - The agenda video shows its complete frame: never crop it. Bottom-align it inside a full-height media region that occupies at least two-fifths of the slide, so the visual remains substantial beside the agenda. - The blooming-flower video, flower-blooming-dark.mp4, belongs to the agenda slide and nowhere else. Never use it on the cover, the closing ask or any other slide; give those their own footage or a photograph. - Real text in real elements. A slide is not an image of a slide. - One idea per slide. If it needs two sentences to state, it is two slides. PACING ====== This is what makes a deck interesting, and it is not colour. A boring deck is almost always a deck where every slide is the same shape. - Pick the layout from the sentence, not the sentence from the layout. Write the line first, then choose the slide that fits it. - Never two consecutive slides of the same layout. If two facts want the same shape, one of them is the wrong shape. - Change ground at least every third slide. Light, dark and deep in rotation is the rhythm. Forest is a beat, not a rotation: use it for a section or statement slide, at most once every few slides. - Give the audience a beat every four to six slides: a section divider, or a statement with nothing else on it. - Twenty-five words per slide, counting every visible word — kickers, labels and numerals included. Twelve on a statement slide. - The data layouts — chart, donut, timeline, journey, infographic — and the agenda are outside that count, because their repeated text is labels rather than prose. They get their own budget: one label and at most one line of explanation per item, and nothing else. - A labelled diagram earns its words by taking them off the slide. If the lede still explains what the figure already shows, cut the lede, not the labels. - An agenda belongs near the front of a deck long enough to have parts, and again before each part with aria-current on the item you are reaching. In a deck of eight slides it is a slide nobody needed. - When an agenda is needed, use the agenda-video layout. There is no text-only agenda alternative: the quiet looping visual gives the room a paced opening without competing with the list. Keep the whole video frame visible, bottom-aligned, and at least two-fifths of the slide wide. - Five items in a list, eight words each. A sixth item is a second slide. - Use kickers and numbering sparingly. A kicker earns its place only when it adds context the title does not, so it is not on every slide. Numerals mark real order — the agenda, steps, a timeline, a section mark — and never decorate tiles, columns or content slides. - At most one accent per slide. None is fine — a statement carries itself. A second accent on the same slide is a defect. - The final ask uses a full-bleed photograph or muted background video with the deep-theme overlay. Never a flat yellow closing ground. - Open on a cover and close on the ask. Everything between is yours. - A number worth saying out loud is worth a metric slide of its own. - Every third slide carries a photograph, screenshot, or portrait. Three consecutive text-only slides is a defect. - A founding, scale, or company-facts slide is never metrics alone. Pair it with an editorial image — use split-photo. IMAGES ====== Decks go dull when photography is treated as optional. These rules sit beside pacing. - Every deck needs at least three photographs: one on the cover or opening beat, one grounding a company or product claim, one showing people or customers in context. - Portraits for people. Photography for place and product. If the slide mentions where you are or what you do, show it. - Use flux-slide--image when the photograph carries the point on its own. Use flux-slide--split-photo when copy and metrics share the slide with it. - The closing ask always uses a meaningful full-bleed photograph or muted background video beneath the deep-teal overlay. The visual supports the action; it is not generic texture. - Cover and closing may use a muted looping background video under that same deep-teal overlay. Put it in flux-slide__media with muted loop playsinline data-flux-video, keep the Flux pause control as a sibling, and do not put background video on any other layout. - The agenda uses the video-backed agenda archetype. Keep its visual quiet, decorative and dark enough that the list remains the point. Use the complete uncropped frame, align it to the bottom, and retain at least two-fifths of the slide for the media. - src may be a URL or a path under /decks/assets/. Alt text is mandatory and must describe what is in the frame, not repeat the slide title. - Never leave a slide that mentions a place, product, or team without a visual of that thing. ACCENTS ======= Set data-accent on a slide to choose its accent. It colours type and data: the oversized mark, the list and agenda numerals, chart bars, a donut arc, a timeline date. core voyage pex edge agents quest circle It never draws decoration — no bar on the edge of a card, no rule beside a label. A product accent has no guaranteed contrast, so it never carries a word. Colour behind text comes from data-flux-theme. The closing slide uses deep over a full-bleed photograph or muted background video, with the built-in teal overlay preserving contrast. The cover may use the same treatment. DIAGRAMS ======== Draw diagrams as inline SVG inside flux-slide__figure. Inline, never linked: a linked image has to name its own colours and can only suit one theme. Split it the way the deck layer expects. Appearance comes from classes, which carry the roles; geometry stays in the markup as SVG attributes, because a viewBox is in user units and a rem token resolves to the wrong size inside one. Classes: flux-figure__frame outlined box flux-figure__panel filled box — the part the slide is about flux-figure__link connector flux-figure__label mono uppercase name flux-figure__note a few words of plain language flux-figure__value a token name or other literal Attributes: x y width height rx d viewBox stroke-width font-size stroke-dasharray Never set fill or stroke on the root: it inherits onto the text and hides it. Give the role="img" and an aria-label that states what the diagram shows, in full. The labels inside are then decoration to a screen reader, so the aria-label is the diagram. To reveal the parts in the order you explain them, wrap them in . Each direct child is one stage, up to six, and they fade in sequence when the presenter reaches the slide. Without flux-deck.js every stage simply shows — the build is an enhancement, never the difference between a readable diagram and an empty box. LAYOUTS ======= 18 layouts. Pick from the sentence you have already written. If none fits, say so and propose one — inventing a layout is the same defect as inventing a component. COVER ----- Use when: The deck opens. Once, at the front. A full-bleed photograph or muted background video under the deep-teal overlay is allowed; type-only on deep remains valid. Not when: Never for a section break — that is the section layout, and it looks different on purpose. Markup:

Platform review · Q3

Connect ships to every tenant

Vera Lindqvist · 18 August 2026

AGENDA ------ Use when: Near the front, to tell the room the shape of the next twenty minutes. This video-backed layout is the agenda type for every deck. Its complete video frame is bottom-aligned in a media region at least two-fifths of the slide wide. Repeat it before a part begins, with aria-current on the item you are reaching. Not when: For content. An agenda names the parts of the deck; a list of arguments is the list layout. A four-slide deck does not need one. Markup:

Agenda

What we’ll cover

  1. Where we are today

    Product status, go-lives, and key milestones from the year.

  2. What customers told us

    Themes from advisory boards, support, and the field.

  3. The roadmap ahead

    Priorities and innovation themes for the next four quarters.

  4. How we get there

    Teams, timelines, and what we need from each other.

SECTION ------- Use when: A divider between parts of the argument. It exists to give the room a beat. Not when: For a slide that carries content. A section slide says where you are, nothing else. Markup:

Part two

What the migration cost

STATEMENT --------- Use when: One sentence that deserves the whole room. The most underused slide in any deck. Not when: For a sentence that needs support. If it needs a caption, it is a split. Markup:

Every booking now clears in under four seconds.

METRIC ------ Use when: A number worth saying out loud. One, or up to three abreast. Not when: For four or more numbers. That is a table. For founding year, headcount, revenue, or scale — use split-photo, not metric alone. Metrics without a photograph read as a spreadsheet. Markup:

Throughput

3.9s Median clear time Down from twenty-one seconds at the start of the quarter.
99.98% Availability Two minutes of degradation, all of it planned.
CHART ----- Use when: One series, four to seven bars, where the shape of the change is the point. Each bar carries its value as --flux-bar, a percentage of the plot. Not when: For two series, or for a trend with many points. A deck bar chart compares a handful of things; anything denser belongs in the document behind it. Markup:

Median clear time · seconds

Every release took time out

  1. 21.4

  2. 16.2

  3. 9.8

  4. 5.1

  5. 3.9

  1. Q2 '25
  2. Q3 '25
  3. Q4 '25
  4. Q1 '26
  5. Q2 '26
DONUT ----- Use when: One proportion, stated next to what it means. The ring is drawn on a circumference of exactly 100, so a segment is written as its percentage. Not when: For four or more segments, or for anything that is not a share of a whole. A donut sliced five ways is a table nobody can read. Markup:

Migration

68% of tenants are on the new engine

The rest are scheduled before the end of the quarter.

INFOGRAPHIC ----------- Use when: One figure that carries the claim, with two or three that support it. The hierarchy is the point. Not when: For figures of equal weight — that is the metric layout. If you cannot say which number leads, you have a metric slide. Markup:

Twelve months of Connect

1.2M Bookings cleared Through one engine, on one contract, in one currency model.
41 Tenants live
0 Rollbacks
SPLIT ----- Use when: An argument on one side and its evidence on the other. Use --split-wide when the text outweighs the figure. Not when: For two competing positions. That is compare, and the seam between them matters. Markup:

Before

Six systems, one booking

Every handoff was a place a reservation could quietly stop existing.

SPLIT WITH PHOTO ---------------- Use when: Copy on one side and an editorial photograph on the other. The company-facts shape: founding story, scale metrics, or product context beside a place, landscape, or operators in the field. Not when: For a diagram or annotated screenshot — that is split with an inline SVG. For a photograph that carries the whole point alone — that is image. Markup:

About Kaptio

Built for multi-day travel. Nothing else.

Founded in Reykjavík to give multi-day travel brands software that fits the industry.

2014 Founded in Iceland
100 People · 17 nationalities
20+ Travel brands
€1.6B 2025 booking volume
Coastal mountains rising from the sea in Iceland at golden hour.
LIST ---- Use when: Genuinely sequential or enumerable points. Five at most. Not when: As the default slide. If every slide is a list, the deck is a document read aloud. Markup:

What changed

  1. One reservation record, owned by Connect.
  2. Every price resolved at write time.
  3. Failures surface in the channel, not the log.
COMPARE ------- Use when: Two positions held against each other. The seam is the point. Not when: For three or more options. Three columns of prose is a table nobody will read. Markup:

Today

Each tenant runs its own pricing rules, and no two agree on rounding.

September

One engine, one rounding rule, and a tenant override that has to be justified.

TIMELINE -------- Use when: When. Three to five dated milestones on one axis. Mark the one you are standing on with aria-current. Not when: For stages without dates — that is the journey layout. For more than five milestones: a timeline read from the back of a room holds about four. Markup:

Rollout

Every tenant by March

  1. Sep 2026 Pilot Four tenants, both currency models, one region.
  2. Nov 2026 General availability Opt-in for everyone already on Connect.
  3. Jan 2027 Default New tenants provision on the engine automatically.
  4. Mar 2027 Legacy off The old pricing path stops accepting writes.
JOURNEY ------- Use when: Who, in order. Stages of a process and the hand-off between them. The seams are where the work changes hands. Not when: For dated milestones — that is the timeline. For a set of points with no order, use list or grid. Markup:

One booking, end to end

  1. Quote Prices resolve once, against the live rate card. Connect
  2. Hold Inventory is reserved for the length of the quote. Connect
  3. Confirm One record, written once, owned by one system. Salesforce
  4. Settle Payment clears against the same record it quoted. Kaptio Pay
QUOTE ----- Use when: Somebody else’s words, where whose words they are matters. Not when: To dress up your own point. A quote from nobody is a statement slide with extra punctuation. Markup:
We stopped reconciling bookings by hand in week three, and nobody has asked to go back.

Operations lead, Tauck

IMAGE ----- Use when: A photograph or screenshot that carries the point on its own. Not when: As background texture behind unrelated text. If the image is decoration, drop it. Markup:
The Connect console showing a reservation timeline.

One timeline

Every state change, in order, with the actor who caused it.

GRID ---- Use when: A taxonomy: four to six things of the same kind, held on screen together. Not when: For a sequence. Order in a grid is ambiguous — use the list. Markup:

The shape of it

Ingest

Supplier feeds land once, and are versioned on arrival.

Resolve

Price and availability settle before anything is written.

Publish

One record, one shape, every channel.

CLOSING ------- Use when: The ask. One per deck, at the end. A full-bleed photograph or muted background video under the deep-teal overlay makes the action tangible. Not when: Anywhere else. This is a closing action, not a reusable image treatment. Markup:
Colleagues working together around a table.

Pilot it with two tenants in September.

Decision needed by 29 August.

SELF-CHECK ========== Run this against the deck before returning it. [ ] Every slide uses one of the layouts. An invented layout is a missing one — say which. [ ] No two consecutive slides share a layout. [ ] The ground changes at least every third slide. [ ] There is a beat — a section or statement slide — every four to six slides. [ ] The last slide is the ask, over a full-bleed photograph or muted background video with the deep-teal overlay. [ ] No slide exceeds twenty-five words, the data layouts aside. [ ] One accent per slide, and no accent carries text. [ ] Every chart bar carries a --flux-bar percentage, and a donut’s two dash values add up to 100. [ ] A chart, a donut or a timeline has a caption saying what it shows. A figure without a claim is decoration. [ ] No raw hex, no raw dimension, no font weight outside 300 and 700. [ ] The deck links flux.css and flux-deck.css, loads no fonts of its own, and has no var(--flux-…) with a fallback value. [ ] Every slide ground is a theme or forest. No story, chapter or persona has its own colour. [ ] npx flux-check passes on the deck file. [ ] Every readable pairing uses a theme ground, so contrast stays at WCAG 2.2 AA. [ ] Every image has real alt text, and no slide is a picture of text. [ ] At least three slides carry a photograph or screenshot. [ ] If the deck needs an agenda, it uses flux-slide--agenda-video with a muted video and its pause control. [ ] The agenda video is uncropped, bottom-aligned, and occupies at least two-fifths of the slide. [ ] The blooming-flower video appears only on the agenda slide. [ ] Kickers are not on every slide, and numerals appear only where order is the meaning. [ ] No company-facts slide without an accompanying image — use split-photo. [ ] The deck reads correctly with the browser at any window size, because the composition scales as one piece and leftover viewport takes the slide’s ground. VERIFY ====== The mechanical rules are the same ones product UI is held to, so the same check runs: npx flux-check deck.html It exits non-zero on raw colours, arbitrary values, synthesised font weights, transition: all, removed focus outlines, gradients and raw dimensions. Pacing and layout choice it cannot see — those are on you.