TrendingMost audit findings are assertions. These six leave evidence.
Internal · design system

The Mediovsky design system.

Every brand, type, color, spacing and component decision in Mediovsky. It is the oracle: if a component is not documented here, it either belongs to one route (see Site chrome) or it should not exist. When you add or change one, update this page in the same pass.

The page reads in two halves. Unbadged sections are what the site is built from: they load the real stylesheet, so what you see here is what a reader gets, and a change to the stylesheet reaches all 52 articles, every other page on the site and this page at once.

Sections badged Proposal are the library of directions: components drawn for where this could go if it ever became a CMS, some of them older than Mediovsky. They are real design work and they stay here to be drawn from. What they are not is available: the site ships no CSS for any of them, so adopting one starts with moving its CSS into site.css. The build enforces that, and will fail on a page that uses one before it has been promoted.

1 / Foundations

Brand & logo.

The Mediovsky wordmark is non-negotiable. Indigo dot accent (#3C3FDE) is the only brand color. Never recolor, distort, or rebuild the mark.

Logo variants

logo.svg · light bg
logo-dark.svg · dark bg

Sizes & clear space

Default · 48px
Nav · 32px
Min · 24px

Minimum height 24px. Always leave clear space equal to the height of the “M” on all sides.

2 / Foundations

Color.

Indigo accent #3C3FDE is the only brand color. Everything else is neutral. Dark mode uses lifted indigo #7A7DFF for contrast.

Brand accent

Accent#3C3FDE
Accent soft#EEEEFF
Accent (dark)#7A7DFF
Accent soft (dark)#181830

Light theme tokens

TokenValueUse
--bg#FBFAF7Page background, warm white
--fg#15141APrimary text, headings
--fg-2#3A3944Secondary text, body copy
--fg-3#76757FTertiary, meta, captions
--rule#E6E4DCBorders, dividers
--accent#3C3FDEBrand accent, links, kickers
--accent-soft#EEEEFFSubtle accent backgrounds, badges

Dark theme tokens

TokenValueUse
--bg#0E0D12Page background
--fg#EBEAF0Primary text
--fg-2#B8B7C2Secondary text
--rule#23222BBorders
--accent#7A7DFFAccent (lifted for contrast)

Semantic colors

Success#10B981
Warning#D97706
Error#E11D48

Use sparingly. Only for status feedback. Avoid in editorial content (indigo accent is enough).

3 / Foundations

Typography.

One typeface (Inter) used at varied weights and sizes. Editorial mark: light weight (300) for display, regular (400) for body, indigo italics for emphasis (set via <em> with font-style:normal).

Type scale

text-1010px
a micro label, always uppercase: a badge count, a code block’s label, an eyebrow
text-1111px
a label beside content: a category, a timestamp, a table header, a source line
text-1212px
the interface default: navigation, the footer, a breadcrumb, a chip, a tag
text-1313px
an interface size up: a button label, a note, a caption, a pill, a form’s helper text
text-1414px
small running text: a card deck, a table cell, a widget’s label
text-1515px
the site’s own body text, and what sets: a static page, a form label
text-1616px
body text that needs a little more room than the site default
text-1717px
the article’s reading size below 900px, and a summary line
text-1818px
a small heading, or a list inside an article
text-1919px
the article’s reading size at 900px and up. The main reading surface of the publication
text-2020px
the largest size still set as text: an h3, a card title, a lede
display-2424px
a card title in a list, a pull quote on a phone
display-2828px
a section heading, and an article h2 below 900px
display-3232px
an article h2, and a page h1 on a phone
display-3838px
an article h1 below 900px
display-4444px
a page h1 at tablet width, a large figure
display-5656px
a page h1 on a static page
display-6464px
an article h1, the largest size on any reader-facing page

Leading scale

leading-crop0.85
88%

a single large glyph or figure where the ratio crops the line box to the letter rather than setting a rhythm: a drop cap, a stat numeral

leading-flat1
a control’s label, which is one line by definition. Not a reading ratio: it lets min-height and padding decide the control’s height
leading-display1.05
a headline at 38px and up, where the eye reads the shape of the line rather than tracking along it
leading-tight1.25
a heading or a card title: two or three lines that read as one unit
leading-snug1.4
dense text in a small box: a table cell, a date, a stat label, a task list
leading-ui1.55
interface prose and the site’s own body text, which is what sets
leading-body1.65
running prose meant to be read for minutes: the article body

Control sizes

TokenValueWhen to reach for it
--control-sm28pxinside a table row, a card footer, a filter bar, a tag list
--control-md36pxthe default: forms, navigation, pagination, inline calls to action
--control-lg48pxone primary call to action per page, and the only step that clears 44x44

Reading measures, in characters

TokenValueWhen to reach for it
--measure-narrow44chprose that shares its space with something else: a caption, a sidenote, a stat label, a form’s helper text, one column of a two-up grid
--measure-body62chthe default, and what any ordinary run of prose gets
--measure-wide76chprose set under or inside a block wider than the prose column: a caption beneath a full-bleed figure, a note under a wide table

Container widths, in pixels

TokenValueWhen to reach for it
--width-form560pxanything a reader types into: a contact form, the newsletter row, the search box
--width-column740pxone column of prose: the article body, and the static pages that used to disagree with it
--width-bleed1120pxa block that escapes the prose column but stays inside the page gutter: a full-bleed figure, an interstitial
--width-page1240pxthe page shell, every section.wrap on the site

Breakpoints

TokenValueWhen to reach for it
--bp-sm640pxthe phone. One column, and the page gutter narrows from 32px to 20px
--bp-md900pxthe layout. Two columns become one: the article and its rail, every static page, the nav
--bp-lg1100pxwide chrome. The page head, the listing filter bar and the pagination give up their horizontal arrangement
--bp-page1303pxthe page shell gains its gutter. DERIVED, not chosen: --width-page + twice the 32px gutter, minus one

Border widths

TokenValueWhen to reach for it
--border-11pxthe hairline. Every rule that separates one thing from another: a card edge, a table row, a form field, a divider, an underline
--border-22pxthe heavier line, where the border itself carries meaning: a bar marking a quote or a summary, a chapter rule, a focus ring, a stroke drawn from two borders
4 / Foundations

Spacing & grid.

8-point spacing system. 8-column grid with 32px gutter. 1240px max container width.

8-point spacing scale

2
4
6
8
10
12
14
16
18
20
22
24
32
40
48
56
64

Grid

1
2
3
4
5
6
7
8

Press G on any page to toggle live grid overlay.

5 / Foundations

Radius & shadow.

Four steps, plus a pill and a circle, read from the token block in public/site.css rather than written here. A corner tracks the size of the box it is on. Shadow only on sticky and floating elements.

--radius-sm 4px

a small mark: inline code, a kbd, a badge, a chart bar, a thumbnail, an image inside a card

--radius-md 8px

the default box, and every cornered control: a card, a panel, an alert, a form field, a nav item, a callout

--radius-lg 12px

a large block: a figure, a fact box, a stat panel, an accordion, a code block

--radius-xl 16px

a full-width feature: a calculator, a scorer, a quiz, a lead magnet, a hero, an interstitial

--radius-pill 999px

fully rounded on the short axis. Not a size: it draws half the box height, so the control scale decides what a reader sees

--radius-circle 50%

a box that is square and meant to read as round: an avatar, a step number, a bullet, an icon button

Shadows

none · sticky-nav (1) · floating (2) · modal/menu (3)

6 / Foundations

Motion.

Three steps, and the step is chosen by what moves, not by how long it ought to feel. Reach for the one that describes the movement and the tempo takes care of itself.

TokenValueUseExample
--motion-fast120msFeedback under the pointer, where nothing travelsA hover fill, a press, a border lighting up
--motion-base150msThe default: any state change on something already on screenLink hover, the sticky nav’s shadow, the theme repaint
--motion-slow350msSomething entering or leaving the pageBack to top, a toast, the theme icon’s turn
nonenoneFocus ringsAccessibility, instant

Two kinds of movement are deliberately not on this scale, and both say so where they are written with motion-ok:. A value drawing itself (a meter filling, a ring closing, a bar growing) runs from 250ms to 1.1s, because its length is tuned to the distance drawn: that is a fact about the data, not about the tempo of the interface. A loop (a spinner, a pulse) has a rhythm rather than a duration. Everything else is one of the three steps above, and F263 fails the build if it is not. Under prefers-reduced-motion the whole scale is switched off.

Live motion preview
7 / Components

Buttons.

Two shapes only: .pill is the outlined default, .pill--solid the filled call to action. Both hover to accent blue. Do not hand-roll a third: the filled one existed as four slightly different inline copies until August 2026.

Primary actions

Subscribe

Icon buttons

8 / Components

Forms.

We’ll use this for the newsletter only.
This field is required.
9 / Components

Chips & tags.

10 / Components

Cards.

11 / Components

List items.

Text-forward article list used on homepage, category, author, latest. Date on left, content middle, thumbnail right (8-col).

12 / Components

Pagination.

13 / Components

Tabs.

Active tab content area.

14 / Components
Proposal

Alerts & toasts.

Heads up

Your enhanced conversions upload rate is below 90%. Go fix that first.

Saved

Article scheduled for publication on May 28.

Cache stale

Edge cache hasn’t refreshed in 48 hours. Consider manual purge.

Failed to publish

Connection to media server lost. Article saved as draft.

Toast

Article saved to reading list
15 / Components
Proposal

Skeletons & empty states.

Empty state

No results found

Try a different keyword or browse the latest articles.

16 / Components

Iconography.

Stroke icons, 1.6 stroke width, 14-20px. Source: Lucide-style custom. Always currentColor.

search
theme
bookmark
arrow
link
close
menu
check
info
alert
mail
play
17 / Live
Proposal

Badges & labels.

Status pills and disclosure labels. Use to flag content type (Featured, Sponsored), status (Live, Beta, Draft), or recency (New, Updated).

Editorial labels

★ Featured Sponsored Cover story Exclusive Part 3 of 6

Status pills

Live New Beta Soon Draft Scheduled Archived Updated May 27

In context: article card

Sponsored
MarTech

Card with sponsored disclosure label.

May 21 · 12 min
18 / Live
Proposal

Marquee ticker.

Continuous horizontal scrolling band. Pure CSS animation, pausable on hover. Use sparingly. For breaking headlines or issue announcements.

Default: dark band

★ Issue №001 out now/ Cover: Your AI ad strategy is only as good as your data/ Fresh coverage every week/ New series: Performance Max audits/ Adobe Summit 2026 wrap available/ ★ Issue №001 out now/ Cover: Your AI ad strategy is only as good as your data/ Fresh coverage every week/ New series: Performance Max audits/ Adobe Summit 2026 wrap available/

Accent variant

● Live now· Fresh coverage weekly· 9 editorial channels· Independent since 2026· ● Live now· Fresh coverage weekly· 9 editorial channels· Independent since 2026·
19 / Live

Back to top.

Floating button bottom-right of viewport. Appears after scrolling past 600px. Site-wide. Already active on every page.

scroll the page to see the live one →
20 / Live

Theme toggle morph.

Sun and moon icons cross-fade with a 180° rotation when switching themes. Both icons in DOM, opacity flipped by html[data-theme] attribute.

click the toggle in the nav, or this one:

Note: this demo button shares the global toggle logic (any element with #theme).

21 / More components
Proposal

Avatars.

Five sizes, with optional status dot. Use initials as default; image when available. Stack overlapping for multi-author or reader lists.

Sizes

MS
MS
MS
MS
MS

With status

MS
AK
JR

Stack (multi-author)

MS
AK
JR
+5
22 / More components
Proposal

Tooltips.

Hover bubble with arrow. Four positions. Use sparingly. Most labels should be visible without hover.

TopTooltip on top BottomTooltip on bottom LeftTooltip on left RightTooltip on right
24 / More components
Proposal

Search input.

Standalone input with leading icon and trailing clear button. For pages without the ⌘K overlay.

25 / More components
Proposal

Toast queue.

Stacked notifications, auto-dismiss after 5s. Use for transient feedback only. Not for errors that need action.

Article saved to reading list
Subscribed to newsletter
Cache stale. Refresh recommended
Network error. Retrying
26 / More components

Notification bell.

Bell icon with unread count badge. Dropdown shows latest notifications.

New issue №217 is now live.
2 hours ago
Your subscription was confirmed.
Yesterday
Reader survey just opened (5 min).
2 days ago
27 / More components
Proposal

Count-up & sparkline.

Animated numerics for stats. Use on first view, not in re-renders.

Counter

2,048Sample metric
247Articles
9.7%CRM swap rate

Sparkline in stat card

2,048
▲ +6.4%
Readers
4:30
▲ +0:18
Avg. read
99.2%
±0.0%
Cache hit
28 / More components
Proposal

Loading button.

Replaces text with spinner during async operation. Pointer events disabled.

29 / More components
Proposal

Progress stepper.

Multi-step form indicator. Done state is solid, active is outlined, upcoming is muted.

Account
Preferences
3
Subscribe
4
Done
30 / More components
Proposal

Confetti.

Celebration animation after positive actions (subscribed, completed survey). CSS only. No canvas needed for this scale.

Joined ✓

Welcome to Mediovsky. Issue №218 ships Thursday.

31 / Brand & unique
Proposal

Newsletter sticky bar.

Bottom-of-viewport CTA that appears after the user scrolls 60% of an article. Dismissible.

One issue a week. No filler. Sharp coverage of media, tech, and AI business.
32 / Brand & unique
Proposal

⌘K hint pill.

Subtle floating pill on first visit, hints at the keyboard shortcut. Dismiss after one use.

Try search. Press ⌘K
33 / Brand & unique
Proposal

Reading rail.

Floating vertical column beside an article: share, save, TOC, font size. Hidden < 1300px.

article body
progress
circle →
34 / Brand & unique
Proposal

Section dividers.

Five variants for article breaks. Use line for default, ornament for editorial pauses, stars for chapter-like breaks.

Line (default)

Ornament with label

continued

Stars

★ ★ ★

Numbered

02

Accent block

35 / Brand & unique
Proposal

Quote variants.

Five quote styles for different editorial weight. Big for pull-out, small for inline, portrait for testimonials, cols for long.

Big (pull quote)

AI doesn’t fail loudly. It optimizes toward your bad data.

Small (inline)

The better the algorithm gets, the worse bad data hurts.

With portrait

MS

“Most marketing frameworks read better than they perform.”

Mikołaj Salecki, editor

Two columns

Performance Max and Meta Advantage+ optimize confidently toward whatever signal you send them. Messy CRM data and delayed conversions silently corrupt targeting models at scale, and the platforms have no incentive to tell you. The better the algorithm gets, the worse bad data hurts.
36 / Brand & unique
Proposal

Footnote & sidenote.

Footnotes for citation, sidenotes for tangent. Both keep article body clean.

Footnote (bottom-of-article)

[1]
Gartner CMO Spend Survey 2025, n=412 B2B teams. See methodology.
[2]
Internal Mediovsky analysis across 14 audited accounts, Q1 2026.

Sidenote (margin)

Performance Max audits should run monthly, not quarterly. Cross-device match rates erode faster than most teams notice, typically 12-18 percentage points in a quarter.
SidenoteMatch rate erosion is invisible without baselining at campaign launch.
37 / Brand & unique
Proposal

Reading progress circle.

Circular SVG progress, replaces linear progress bar in compact contexts (reading rail, mini player).

60%
5 min remaining
38 / Brand & unique
Proposal

Highlight on hover.

Subtle hover effect on key phrases. The underline grows into a full highlight on hover. Use for callouts inline.

Performance Max optimizes confidently toward whatever signal you send. Messy CRM data and delayed conversions silently corrupt targeting models, and the platforms won’t tell you it’s happening.

39 / Brand & unique
Proposal

Bookmark moment.

Reader selects a passage; a floating action lets them save the quote with the article reference.

“AI doesn’t fail loudly. It optimizes toward your bad data, quietly, on schedule.”

From your reading · Issue №001
40 / Brand & unique
Proposal

Caption styles.

Four caption variants for images: default, italic editorial, source attribution, rich (with label).

A simple caption with no styling beyond muted text.
An italic editorial caption with slightly more weight.
SOURCE: MEDIOVSKY · MAY 2026
Figure 1Modeled signal loss across a 90-day conversion window in Google Performance Max with degraded CRM inputs.
41 / Brand & unique
Proposal

Page transitions.

Four built-in transitions between pages. Use sparingly. Default is fade only.

Default
Fade
Compact
Slide-up
Detail
Cross-fade
None
Instant
42 / Brand & unique
Proposal

Glitch on hover.

RGB-shift glitch effect. Use with extreme caution. Only for one-off emphasis, never on body text.

Sharp insights, smarter growth.

43 / Brand & unique

Accordion.

Native <details> elements styled as a card. Use for FAQ, methodology notes, advanced settings, anything secondary that shouldn’t take vertical space by default.

Card variant

01 What is Mediovsky?

An independent journal of media, tech, and AI business, started in 2026. Each week brings a cover essay anchored by shorter pieces: how-to guides, data analyses, opinion, and the occasional review.

Written for professionals who run digital. Read more about us.

02 How often do you publish?

A cover essay each week, anchored by shorter pieces, plus extra coverage during major industry events.

03 Do you accept guest pitches?

Yes. From working operators only. See our editorial line for what we look for. Two-week turnaround.

04 Can I republish your articles?

Quote freely with attribution (up to ~150 words). Full republication requires permission. Email [email address].

Plain variant (no card)

A Methodology for our data pieces

First-party data from accounts we audit, vendor-published primary sources, peer-reviewed research, and named industry surveys. See full methodology.

B How we handle corrections

Public corrections posted on the original article, with the previous wording struck through. View all corrections.

Built on native <details> for accessibility: works without JS, keyboard-navigable, screen-reader friendly.

44 / Admin actions
Proposal

Dialog: basic.

Centered modal with title, body, action footer. Use in admin for short single-purpose flows: rename, change status, edit one field. ~520px wide.

45 / Admin actions
Proposal

Dialog: form.

For “Add user”, “+ New token”, “+ Manual backup”, “+ New redirect”: multi-field form with submit / cancel.

46 / Admin actions
Proposal

Dialog: danger.

Destructive irreversible actions: delete article, restore backup. Red icon header, typed confirmation for the worst.

47 / Admin actions
Proposal

Confirm.

Smallest possible decision. One line, two buttons. Use for unsubscribe, archive, revoke session.

48 / Admin actions
Proposal

Drawer.

Right slide-in, 480px. Subscriber details, audit log entry, revision view.

49 / Admin actions
Proposal

Sheet (mobile).

Bottom slide-up. Mobile fallback for drawers and dialogs, or for filter / sort.

50 / Admin actions
Proposal

Popover menu.

Anchored dropdown for row ⋯ menus, “Export ▾” buttons.


51 / Admin actions
Proposal

Inline edit.

Edit in place. Click a value in a table row → input. Use for slug, tag name, single-field changes.

52 / Admin actions
Proposal

Page banner.

Top-of-page status. Persistent until dismissed.

53 / Admin actions
Proposal

Decision matrix.

Which UI for which action.

UseUIWidth
Single binary decisionConfirm380px
1-3 fields formDialog · form520px
4+ fieldsDialog · form520-640px
Detailed view-onlyDrawer480px
Destructive irreversibleDialog · danger520px
Row ⋯ menuPopover240px
Quick field changeInline editcell
Filter / sort on mobileSheetfull
Status / system messageBannerfull
Transient confirmationToastauto
54 / Editorial

Code blocks.

A plain pre inside the body. data-label prints the language and the file above it; article-widgets.js adds the copy button. Highlighting is four hand-applied spans, not a library: .c comment, .k keyword, .s string, .n number. Code samples are the one place that keeps straight quotes, because a reader who copies a snippet with curly ones gets something that does not parse.

-- everything that spent and never converted
SELECT search_term_view.search_term, metrics.cost_micros
FROM search_term_view
WHERE metrics.conversions = 0
  AND segments.date DURING LAST_30_DAYS
55 / Article widgets

Article page anatomy.

Everything below this point is styled by public/article.css, which this page loads so the demos are the real components and not a redrawing of them. The chrome in this first table is rendered by the page template from frontmatter and content collections. An author never writes it.

ClassWhat it isRendered by
.article-headthe whole masthead block above the bodytemplate
.breadcrumbHome / category / title trail, with .sep and .cattemplate
.kickerthe accent line above the headline: the category, or the cover-story flagtemplate
.deckthe standfirst under the headlinefrontmatter excerpt
.meta-rowbyline row: .author, .av, .nm, .rl, .details, .sharetemplate
.coverthe lead image, with .cover__img and .cover__caption (.credit)frontmatter image
.body-wrap · .body-grid · .bodythe 8-column grid and the 740px reading column inside ittemplate
.article-faqthe FAQ block, with .faq and .faq__item insidefrontmatter faq
.sourcesthe numbered source list: .src-num, .src-body, .src-org, .src-title, .src-meta, .src-linkfrontmatter sources
.tagsthe tag row under the bodyfrontmatter tags
.end-sharethe share row that closes the articletemplate
.author-biothe author cardauthor collection
.prevnextprevious / next article linkstemplate
.related-sec · .related · .rcardthe read-next grid and its cardstemplate

A body element that carries a citation marks it with a.ref pointing at #src-N. Every marker must resolve to a source in the list, and every source must be cited at least once. tests/frontend.mjs fails the build on either.

56 / Article widgets

Data displays.

Static figures. Every number in one of these must be traced to a primary source in the figure ledger before the piece ships. docs/AUTHORING.md section 6a says when to reach for each.

Big-number apla · .statfeature

One hero figure on a brand panel. The .alt modifier swaps the flat blue for a gradient. data-count on .n animates the number up on scroll.

58%
fewer clicks reach the top organic result when an AI summary sits above it. Ahrefs, 300k-keyword study

Stat grid · .statgrid > .stat

Two to four quiet figure cards. Each .stat is a .n and an .l.

$0.08
average fee increase per unit
40+
distinct fee types once surcharges are counted
$0
monthly marketplace fee on the challenger

Keystat · .keystat

One large figure inline, lighter than an apla and safe to use more than once in a piece.

60%
reduction in manual work from agent-powered optimization, as a single vendor self-reports.TheSmarketers

Trajectory · .trajectory

A value across periods. Bars animate to data-w percent on scroll; .is-peak accents the row that matters. .trajectory__cap carries the source.

2024
$28.8 billion
2025
$33.4 billion
2026
$38.0 billion
2029 (f)
$52.5 billion

US CTV ad spend, eMarketer forecast. 2029 is a projection.

Ranked · ol.ranked

A numbered leaderboard. The number is a CSS counter, so the markup carries no digits: each li is a .rk-name (with an optional small) and a .rk-val.

  1. Amazon AdsRetail media, US net spend$56.1bn
  2. Walmart ConnectRetail media, US net spend$5.6bn
  3. InstacartRetail media, US net spend$1.1bn

Share bar · .sharebar

One stacked bar for a split. Widths are inline percentages on .s1 to .s4 and must add to 100; the key repeats the same classes as swatches.

  • Amazon 79.7%
  • Walmart 8.0%
  • Target 1.5%
  • Everyone else 10.8%

Pros and cons · .proscons

Two columns under one rule: .proscons__col--pro and --con, each a p.w-title and a list.

Keep human

  • Hero images where a face carries the endorsement.
  • Founder, team and customer testimonials.

Use AI freely

  • Backgrounds and textures with no synthetic person in them.
  • Variant generation: sizes, crops, seasonal restyles.
57 / Article widgets

Structural & narrative.

Devices that shape how a piece reads rather than what it counts. Section 6b of the handbook has the editorial rule for each; this is what they look like.

TL;DR · .tldr

Required at the top of every article: 5 to 10 bullets, scaled to length. Carries its own .tldr__label.

TL;DR
  • Agents are production-ready for closed-loop, reversible tasks.
  • 2026 is assisted autonomy: agents act within hard rules, humans approve the big moves.
  • The risk is not the agent. It is an agent optimizing fast toward the wrong goal.

Spotlight · .spotlight

An accent panel: a .k eyebrow, a p.w-title claim, then the argument.

The reframe

Your traffic got smaller and more valuable at the same time.

If you report organic sessions, AI summaries read as a slow catastrophe. If you report revenue per visit, the same period reads as a purge of traffic that was never going to buy.

Factbox · .factbox

The quieter, bordered cousin of the spotlight: an aside or a definition.

The line, drawn plainly

Give to the agent: reversible, measurable execution: bids, budgets, rotation, QA.

Keep for the human: the objectives, the guardrails, and any move that cannot be cleanly undone.

Compare · .compare

Two readings under one rule, not two cards. .win marks the side that carries the point. The .shift variant uses .then, .arrow and .now instead.

Manual shopping

~3.7x ROAS. You control audiences, placements, budgets. And you do the work.

Advantage+ Shopping

~4.5x ROAS, ~32% lower CPA. The AI controls almost everything. You control the inputs.

Flow · .flow

The light vertical step list: a numbered circle, a title, one paragraph. Three to five steps.

1

Reactive

Capability exists because someone bought it once. No owner, no review cadence, no roadmap.

2

Aware

An owner exists on the org chart. Procurement happened. Adoption did not.

3

Capable

Workflows are documented, outputs are measured, and no single person carries the pillar.

Process · .process

The richer step-by-step: a connecting spine and a .tag per step. Use it when the method itself is the point.

A

AI, the capability layer

Where intelligence enters the work, through prompts, models and agents. Most teams operate at assistive and call it agentic.

Capability
D

Digital, the platform

The floor the rest sits on: strategy, channels and data infrastructure as one engine, or a folder of subscriptions that share a logo.

Platform

Checklist · ul.checklist

Scannable takeaways with ticks. Body links and a.ref markers work inside it.

  • Qualify first: reach 25+ weekly conversions with clean signal before the campaign gets majority budget.
  • Cap existing customers at 25-30% so the algorithm hunts new demand instead of re-buying your own.
  • Judge it on incremental ROAS after the learning phase, not the blended headline.

Timeline · .timeline

Dated milestones. .is-now marks the current one.

Days 1-30 · Diagnose
Inventory every tool, automation and dashboard. Identify the one pillar at the lowest level: that is the constraint.
Days 31-60 · Lift
One pillar, one level, in 30 working days. Three concrete moves, one named owner each.
Days 61-90 · Verify
Re-measure the one metric. Did it actually move, or did the noise?

Accordion · .accordion

Native details, no JavaScript: a summary and an .accordion__body. For optional depth the reader can skip.

What counts as a primary source?

The document that contains the figure, not an article reporting it. A vendor blog citing a study is not the study.

Does a paywalled source count?

Yes, if you opened it and quoted the figure verbatim into the ledger.

Pullquote · .pullquote, and a sourced blockquote

The pullquote is a sharp line from the piece itself; the blockquote is somebody else’s words, with a cite.

The better the algorithm gets, the worse bad data hurts.
AI does not fail loudly. It optimizes toward your bad data, quietly, on schedule.Mikolaj Salecki

Callout · .callout

A short aside in the flow of the argument: a strong label, then the point. Lighter than a factbox, and it does not break the column.

The operator’s read Do not restructure around the tooling. Restructure around accountability: who specifies the work, who validates it, and whose name is on the number.

Glossary term · span.term

An inline jargon term that reveals its definition on hover or focus. Needs data-tip and tabindex="0", so it works on a keyboard. .term--flip anchors the bubble to the right edge when the term sits near the end of a line.

Most teams still report on ROAS alone, which hides whether the revenue was incremental.

58 / Article widgets

Breaking the column.

The body sits in a 740px column. These devices deliberately escape it. On an article they run to 92vw, capped at 1120px; in the boxes below they are clipped to the demo, so judge the treatment, not the width. One or two per long piece, never back to back.

Interstitial · .interstitial

A full-bleed statement band that stops the reader between sections: .k eyebrow, .big line, .src attribution. .is-dark swaps the blue for near-black.

The number that should bother you

Only 51 cents of every programmatic dollar reaches the page.

ISBA and PwC Programmatic Supply Chain Study

Chapter divider · h2.chapter

A numbered break announcing a new major section. It is a real h2, so it lands in the outline.

04Then test the label, do not fear it

Bleed wrapper · .bleed

Makes any block go wide without the interstitial treatment: wrap a table or a chart in it. .bleed--wide caps at 960px instead of 1120px.

Anything can bleed

A table, a chart, a factbox. The wrapper only changes the width.

59 / Article widgets

Lead generation.

A piece carries either a lead magnet or a content upgrade, never both, and only when the offer is real. Whatever the CTA points at must exist before the article ships.

Lead magnet · .leadmagnet

The title is p.w-title, not a heading: article.css styles .leadmagnet .w-title and nothing else, and a promo block has no business in the document outline. .leadmagnet--cover adds a .leadmagnet__cover image on the left.

Free · one-page PDF

The 2026 supply-path audit checklist

Every fee layer, gate and reconciliation step, on one page you can take into a planning meeting.

  • The four fee layers and what each one hides
  • The ads.txt and take-rate clauses to demand
Get the checklist →

Content upgrade · a.upgrade

The lighter inline cousin: one line mid-article, a .upgrade__tag, a .upgrade__txt and a .upgrade__go.

60 / Article widgets

Interactive tools.

Driven by public/article-widgets.js, which this page loads. Roughly one article in three gets one, rotated across the palette. Two rules the build enforces: the production CSP has no unsafe-eval, so a calculator formula is parsed, never evaluated; and every widget must work with a keyboard.

Donut · .donut

One share as a ring. JS draws and animates the SVG from data-pct; the caption lives in .donut__t.

65.51% of DOOH spend is projected to run programmatically in 2026, the largest segment of the channel. Fortune Business Insights, 2026 forecast

Bar chart · .barchart

Categorical, not time. Bars animate to data-w percent on scroll; .is-peak accents one row.

Experimenting with agents62%
Scaling in one or more functions23%

Line chart · .linechart

A trend over time. The whole chart is one empty div: JS reads data-points, data-labels and data-cap and draws the SVG. Points and labels must be real and sourced.

Toggle · .toggle

Tabbed panels for a which-of-these-are-you branch. The tab strip is a real radio-style group, arrow keys included.

Use the official MCP server. Reporting is read-only work, so the worst case is a wrong answer you can check, not a wrong charge you cannot undo.

Calculator · .calc

A named formula in data-formula over input[data-field] values, with data-format and data-dec shaping the output. Every field needs a real label and id.

Do the math

Blended ROAS to a rough incremental floor

Strip out the existing-customer conversions that would likely have happened anyway. What is left is a rough floor for incremental ROAS on new customers.

%
2.7xrough incremental ROAS on new customers

A directional estimate only. Validate with a geo or audience holdout before you act on it.

Scorer · .scorer

Weighted checkboxes that must sum to 100. data-gate and data-critical exist so a half-configured stack cannot read as Ready on total alone.

Self-check

Can your warehouse do the CDP’s job?

0/100
Exposed

Quiz · .quiz

Each option carries a data-score; the total reveals the highest .quiz__band[data-min] it clears. The bands must cover 0, or a reader who scores nothing sees nothing.

How often does this task run?

What happens if it runs wrong?

Leave it manual

Rare, judgment-heavy or expensive to get wrong. Automating it buys you little and risks a lot.

Automate it

Frequent, rule-based and cheap to undo. This is exactly the work a scheduled job should own.

Before / after and hotspots

Both need a real image pair or an image worth exploring, so there is no honest demo here. The markup, for when there is one:

<!-- draggable slider between two images -->
<div class="beforeafter">
  <img src="/img/after.webp" alt="..." width="1200" height="800">
  <div class="beforeafter__before"><img src="/img/before.webp" alt="..." width="1200" height="800"></div>
  <span class="beforeafter__tag is-before">Before</span>
  <span class="beforeafter__tag is-after">After</span>
  <input class="beforeafter__range" type="range" min="0" max="100" value="50" aria-label="Reveal the after image">
  <span class="beforeafter__handle"></span>
</div>

<!-- pins that reveal a note on click -->
<div class="hotspots">
  <img src="/img/screenshot.webp" alt="..." width="1200" height="800">
  <button class="hotspots__pin" style="left:22%; top:38%" data-note="<b>Budget</b> is the field most teams set once and never revisit.">1</button>
  <div class="hotspots__note" hidden></div>
</div>
61 / Media
Proposal

Images & gallery.

Standard aspect ratios: 16:9 (cover, video), 16:10 (article thumbs), 1:1 (Editor’s picks), 4:5 (portrait), 21:9 (cinematic hero), 3:4 (issue cover).

Aspect ratios

Gallery (mosaic)

62 / Media
Proposal

Audio & podcast.

Reserved for when we ship audio editions and the podcast. Compact player for inline use, full card for episode pages.

Inline audio player

Issue №001: audio edition (read by author)

04:3215:14

Podcast episode card

Mediovsky podcast · Episode 14

What broke in performance marketing this quarter, and why nobody noticed.

45 min·Recorded May 20
63 / Media
Proposal

Video.

11:42
64 / Media
Proposal

Embeds.

Frames for YouTube, Vimeo, X/Twitter, Mastodon, GitHub gist, CodePen, Figma. Always 16:9 or auto.

YouTube embed · 16:9
X / Twitter embed
GitHub gist
Figma embed
65 / Data
Proposal

Stats & KPIs.

2.0K
Sample metric
▲ +6.4% vs last month
247
Articles published
8 this month
4:30
Avg. read time
▲ +0:18 vs Q1
99.2%
Cache hit rate
edge · 24h window
66 / Data
Proposal

Tables.

ChannelArticlesAvg. readReads (30d)Status
PPC3810:248,412healthy
SEO319:186,205healthy
AI & Data4211:0211,304healthy
MarTech299:454,118slow growth
E-Commerce248:093,002needs attention
67 / Reference

Site chrome.

Page furniture that belongs to one route or to the shell around every route. Nothing here is a demo, because none of it is reusable: each one exists in exactly one place and this is the map of where.

ClassWhat it isLives in
.skip-linkthe first thing in the tab order on every page: jump straight to the contentBaseLayout.astro
.page-headthe title block a listing or a standalone page opens withPageHeader.astro
.pagenavprevious / next between pages of a listingPager.astro
.pagination--barethe pagination row without its box, for the homepageindex.astro
.filterbarthe category filter above the latest listinglatest/[...page].astro
.ar-cardthe tall cover card in the homepage archive strip (__cover, __num, __date, __title, __meta)index.astro
.search-overlaythe full-screen search layer the shortcut openssite.js
.bell-wrapthe notification bell and its dropdown in the headerBell.astro
.saved-badgethe count on the reading-list icon; .is-saved is the saved state of a Save buttonNav.astro, site.js
.err-hero · .err-contentthe 404 page404.astro

Anything genuinely reusable belongs above this section with a live demo. If you find yourself adding a second use of something listed here, that is the signal to promote it, not to copy it.

68 / Reference

Voice & tone.

Editorial voice principles. Keep these in mind when writing UI copy, microcopy, and article body.

{/* style-ok: the right-hand column is the wrong spelling, on purpose */}
PrincipleDoDon’t
Direct“AI optimizes toward your bad data.”“AI may potentially optimize...”
Specific“55-80% of SERPs shifted in 12 days.”“Lots of SERPs shifted.”
Practical“Block 90 minutes on Monday...”“Consider exploring options...”
Skeptical“Most frameworks read better than they perform.”“This framework will transform your business.”
American English“optimization, behavior”“optimisation, behaviour”
69 / Reference

Naming conventions.

TypeConventionExample
CSS classesBEM-lite.card · .card__title · .card.is-active
State classesis-X / has-X.is-open · .is-active · .has-error
JS hooksdata-* attrsdata-pane="A" · data-r="insight"
localStorage keysmediovsky-Xmediovsky-saved · mediovsky-theme
Custom eventsmediovsky:X-Ymediovsky:saved-changed
IDs (unique)camelCase#savedBadge · #navDrawer
Pageskebab-case.astrostyle-guide.astro · [slug].astro
ComponentsPascalCase.astroPageHeader.astro · ArticleListItem.astro
Article slugsangle-specific, no yearctv-budget-gap.md, not ctv-2026.md

This page is the oracle: if a component is not here, it is either site chrome (the section above) or it should not exist. When you add or change one, update this page in the same pass. It loads article.css and article-widgets.js directly, so the article demos cannot drift from the real thing; the site-chrome demos use the global stylesheet for the same reason. Anything drawn with inline styles in a demo box is a mock and will go stale, which is how the editorial sections rotted before August 2026.