SG-00Cover sheet · Drawing set SG · Instant ad snapshot

Rev B · Nov 2026 · after the simplification
Style guide · The instant snapshot · Nov 2026

See where you stand, in the feed and in AI answers.

How the studio’s free snapshot looks, reads and behaves, drawn the way we would document a building: every part at 1:1, so the dimensions you read are the pixels we ship.

Headline: the start page’s own h1
Sheet
SG-00
Scale
1:1 px
Rev
B
Date
Nov 2026
Project
Instant ad snapshot · the free Meta and AI snapshot
Studio
Ground
Light only
Symbols
48Dimension, px Callout, see the plate’s key Image area (ad preview) Status light: high, medium, low
General notes

Drawn to the simplified studio system (docs/reference/studio-style-system.md): the colour tokens on SG-02, eight type sizes, five radii, no shadows. Contrast ratios are WCAG 2.2, computed from the values on SG-02; on-dark alphas are composited over each dark ground. Sample business: Sample Burger Co., with Competitor E and Competitor J. Prices as the live site states them.

SG-01One mark, one bar to start from.

Logo · studio top bar

Detail A · Logo

Drawn 2:1
Stone
Card
Gradient
  1. Diamond. 13 px square turned 45°, square corners, --accent. It stays orange on every ground.
  2. Word mark. Geist 600, 17 px (--fs-read), −0.01em, gap 10. The only 600 in the system. Ink on stone and card, --on-dark on the gradient.
  3. Name. Always “RD&D Studio”. Never a person’s name beside it.

Detail B · Studio top bar

On the eras gradient · R 22
Get a free snapshot 44
76 44

Phone · under 700 px

Get a free snapshot
390
  1. Logo in white. The bar’s padding is 16 top and bottom, 44 at the sides on desktop.
  2. Services · About · Contact. Geist 14 (--fs-small), --on-dark-2: 4.99:1 on the top stop, 4.71 on the bottom.
  3. The only call to action. Outline pill, R 999, 1.5 px --line-on-dark, --on-dark text 6.27:1; hover takes the border to --on-dark. ↗ because it opens the start page.
  4. Phones keep the logo and the pill only; the section links move to the page.

SG-02Ink on stone, one orange for action.

Token · value · role · contrast

Detail C · Palette

From tokens.css · ratios WCAG 2.2
TokenValueRoleContrast
C1 · Grounds
--bg#e9e8e5Page ground, warm stoneGround
--card#fafaf8Panels, the checklist card, the checks dialogGround
--paper#ffffffFields, stat tiles, the selected tab and the panel it opensGround
--hover#dfddd9Hover fills, your row in the category table, image wells12.42ink · 6.72ink-3 · 4.10muteNo mute text
C2 · Ink
--ink#1e1d1bHeadings, ink pills, table rules, the rust pill’s hover13.75bg · 16.12cardAA
--ink-3#4a4845Body copy, fix text, the other tab, the ink pill’s hover7.44bg · 8.72cardAA
--mute#6a6864Secondary text, labels, placeholders, hints, the italic phrase4.54bg · 5.56paperAA
C3 · Lines
--hair#dcdad5Row rules, the other tab, progress track1.34cardDecorative
--hair-2#cfcbc4Control, tile and card borders, waiting ring, other brands’ bars, disabled Buy1.55cardDecorative
C4 · Accent · action and “working”, never a grade
--accent#e8743bMarks only: logo diamond, working arc and bar, selected tab line, bullets2.87cardNot text
--accent-ink#ab4c1bOrange text, field errors, the focus ring on light grounds, the rust pill4.53bg · 5.55white on itAA
--accent-tint#f6e1d3The peach offer banner, the empty ad slot, the making fill13.34ink · 4.40accent-inkInk text only
C5 · Status lights · high, medium, low · grades only: marks, dots, chip borders and tints
--signal-green#2e8b57Grade dots A–B, chip border, done ring, the ✓ in the checks4.06card · 4.25white on itMark only
--signal-green-tint#dff0e6Grade chip A–B, pass badge14.23ink on itAA
--signal-yellow#d9a21bGrade dot C, chip border, “missing” step, untraced number2.20card · 7.33ink on itDot + label
--signal-yellow-tint#f8edccGrade chip C, a number held for review14.42ink on itAA
--signal-red#c8372dGrade dots D–F, chip border4.97card · 5.20white on itMark only
--signal-red-tint#f7dcd8Grade chip D–F12.98ink on itAA
C6 · Dark grounds
--grad-eras#655e67 → #7f5844 → #a3491aTop bar, studio hero, start page5.96on-dark · 4.71on-dark-2, lowest stopAA
--grad-now#556360 → #3e685c → #286b57The snapshot form6.29on-dark · 4.99on-dark-2AA
--studio-panel#55524dServices and pricing panel7.78on-dark · 6.07on-dark-2AA
--studio-card#605d57Service cards, the lead (free) card included6.56on-dark · 5.22on-dark-2AA
C7 · On dark · alphas, measured composited over each dark ground
--on-dark#ffffffText and marks on dark grounds, the focus ring there5.96lowest, eras bottomAA
--on-dark-2rgb(255 255 255 / .84)Secondary text on dark: nav links, the italic phrase, ledes, placeholders4.71eras bottom · 6.07panelAA
--line-on-darkrgb(255 255 255 / .4)Rules, outline pills, card and field borders on dark2.22–2.67on the groundsDecorative
--hover-on-darkrgb(255 255 255 / .09)Hover fill behind on-dark text5.00on-dark on it, lowestOn-dark text only
--field-on-darkrgb(0 0 0 / .18)Form fields on dark7.86on-dark · 6.08on-dark-2 placeholderAA
--grad-eras · top bar, start page

#655e67 → #7f5844 → #a3491a--on-dark 6.27 / 6.21 / 5.96. --on-dark-2 4.71 on the last stop.

--grad-now · snapshot form

#556360 → #3e685c → #286b57--on-dark 6.29 to 6.30. --on-dark-2 4.99 or more.

--studio-panel · services

#55524d · card #605d57--on-dark-2 6.07 on the panel, 5.22 on the card.Every service card, the lead one too: --studio-card, 1 px --line-on-dark

  1. Contrast is the token as text (or white on it, where it is a fill), on the grounds it meets. 4.5:1 for text, 3:1 for marks and focus rings.
  2. Badges. AA passes at any size. Yellow: allowed only where named. Red: never text. Gray: rules and borders.
  3. On-dark tokens are white or black at an alpha. Each ratio is the alpha laid over the ground first, on every gradient stop and both studio grays; the table prints the lowest.
  4. Status-light colours never set text. --signal-green is 4.06:1 on card. Text on a tint stays ink.

Note · Retired in the Nov 2026 simplification

A record · not for use
RetiredUse instead
--on-grad--on-dark
--on-grad-mute · --on-grad-green · --studio-mute--on-dark-2
--studio-ink-2--on-dark
--on-grad-deep--ink
--studio-hair · --studio-hair-2 · --studio-field-line--line-on-dark
--studio-field--field-on-dark
--studio-card-lead--studio-card
--ink-2--ink (text) · --ink-3 (ink pill hover)
--accent-deep--ink (rust pill hover)
--accent-wash--accent-tint
--green · --green-ink--signal-green (marks)
--hint · --faint--mute (text) · --hair-2 (graphics)

The styles before this change are git tag styles-before-simplify. Sizes and radii were folded the same way: any other size to the nearest of the eight steps, any other radius to the nearest of the five.

Detail D · Status lights

The grade colours · A to F
A72 · R 16

High

Mark #2e8b57Tint #dff0e6

A every check · B 80%+

Meta ads grade A–B
C

Medium

Mark #d9a21bTint #f8edcc

C 60% to 79%

C
F

Low

Mark #c8372dTint #f7dcd8

D 40% to 59% · F under 40%

D–F
  1. Every grade letter is ink on the light’s tint, with a 1 px border in the light’s colour: 14.23:1 on green, 14.42 on yellow, 12.98 on red. Never white on the solid light: white on --signal-green is 4.25:1.
  2. The border is the light. Ink on the tint carries the letter; the 1 px border in the light’s colour carries the grade, so the three read apart without colour on the text.
  3. Bands are the live key under the category table: “Meta ads grade A–B · C · D–F”. Text on a tint stays ink; the dot carries the colour.

SG-03Every pair measured, and the system graded.

WCAG 2.2 · AA

E1 · Text on every ground

Text token × surface
Text token--bg--card--paper--accent-tint--hover
--inkHeadlines, labels in a row 13.75AA16.12AA16.84AA13.34AA12.42AA
--ink-3Body copy 7.44AA8.72AA9.11AA7.22AA6.72AA
--muteSecondary, placeholders, hints 4.54AA5.32AA5.56AA4.40Large4.10Large
--accent-ink Kickers, errors, fix numbers 4.53AA5.31AA5.55AA4.40Large4.09Large

On dark grounds · alphas composited over the ground

16.84--on-dark on --ink
5.55--on-dark on --accent-ink
5.96--on-dark, eras bottom
4.71--on-dark-2, eras bottom: the lowest
5.22--on-dark-2 on --studio-card
6.08placeholder, --field-on-dark
AA 4.5:1 and up, any size Large 3:1 to 4.5:1: 24 px regular or 18.66 px bold, or a mark. Not used for text on that ground.
  1. The yellow cells are designed out. Orange and mute text never sit on a tint or a hover fill; your row in the table sets its secondary text in --ink-3. Placeholders are --mute on paper, 5.56:1.
  2. The lowest text pairs in use are --accent-ink on --bg, 4.53:1, and --on-dark-2 on the eras gradient’s last stop, 4.71:1. Cells print the computed ratio to two places, not the token comment.

E2 · See the checks

The system on its own lights
BThis guide

11 of 12 of our standard

  • Contrast AA on every text pair

    Lowest in use: accent-ink on stone 4.53:1; on dark, --on-dark-2 on the eras gradient 4.71:1

    Pass
  • Placeholders pass

    --mute on paper 5.56:1; --on-dark-2 in a dark field 6.08:1

    Pass
  • Focus rings reach 3:1

    2 px --accent-ink on light grounds (5.31 on card); --on-dark on dark (5.96 or more)

    Pass
  • One accent colour

    Orange for marks, accent-ink for its text and the rust pill

    Pass
  • Lights are marks and tints only

    Grade letters ink on the tint with a 1 px border in the light, 12.98:1 or more

    Pass
  • No shadows

    Depth is card on ground; the selected tab is marked by its 3 px accent top border

    Pass
  • Eight sizes, three weights, five radii

    300, 400, 500; 600 in the logo only. 22, 16, 10, 999, 50%

    Pass
  • No text under 11 px

    --fs-label is the floor: mono labels and the YOU tag

    Pass
  • Every number sourced

    Ad data, ad copy or the brand’s own site

    Pass
  • Every dead end has a screen

    No website, no Facebook page, no live ads, daily limit

    Pass
  • Speaks as the studio

    “We”, never a personal name

    Pass
  • Ink pill hover is --ink-3

    The start page’s Send and Continue still take the site-wide .btn hover, --ink-2

    Fix
  1. Graded like a brand’s ads: A when every check passes, B at 80% or more.
  2. One open fix, listed rather than hidden: give the start page’s ink pills the --ink-3 hover the ad sample already uses.

SG-04Three families, each with one job.

Geist states · Newsreader explains · Geist Mono labels

Detail E · Type scale

Fluid sizes: min → max, each reaching its max at its own width (SG-11)
TokenSpecimen, at 1440 px SpecUse
--fs-h1 40 → 66

See where you stand, in the feed.

Geist 300−0.04em · line 1.02. Phrase: Newsreader 300 italicHero headline: the studio page and the start page, on the gradient.
--fs-h234 → 56

Our services

Geist 300−0.035em · line 1.05Page and panel titles on the studio page.
--fs-h324 → 32

You launched 10 new Meta ads in the last 30 days. That’s more than Competitor E and Competitor J.

Geist 500 + 400−0.03em · bold in ink, the rest in ink-3. Stat numbers: 300, tabularSnapshot headline, card titles, stat numbers.
--fs-lede19 → 22

Enter your website. We read your live Meta ads next to your competitors’, ask AI assistants about you, and make you three new ads.

Newsreader 300line 1.45 · ink-3One intro under a headline; service card titles and subheads in Geist.
--fs-read16 → 17

Name the dish in the first line. Pulling your live ads and your competitors’.

Geist 400 / 500line 1.55Fix text, checklist steps, field labels and what you type.
--fs-body15

New ads in the last 30 days, and the mix of ads running now.

Geist 400line 1.5UI text: card intros, table rows, tab and button labels.
--fs-small14

Image ad, in feed (4:5) and Stories (9:16) sizes · 3 of 3 picked

Geist 400line 1.4Secondary UI text: counts, hints, field errors, captions, tile labels, sources.
--fs-label 11

Meta ads snapshot for Sample Burger Co.

You
Geist Mono 400 uppercase · +0.09em · the floorKickers, table heads, the YOU tag. Nothing smaller.
  1. Specimens are set at their 1440 px size, the width these sheets are drawn at. Below that the clamps step down to the min. Any other size maps to the nearest step by its desktop value.
  2. 11 px is the floor for any text, mono or sans, on every sheet and every screen.
  3. Headline pattern: a sans statement and one italic serif phrase, --on-dark-2 on the gradient, mute on light. The snapshot’s own headline swaps the serif for weight: 500, then 400.
  4. Three weights: 300 display, 400, 500. 600 only in the logo. Self-hosted on the site from @fontsource, Latin only; no Google Fonts request in production.

SG-05Soft corners, no shadows, room to breathe.

Spacing steps · five radii · no shadows

Detail F · Spacing

Bars drawn 1:1
8label · value
12checklist rows
16--gutter, phone
24--gap
44touch target
64--gutter, 1440
112--section, max
  1. 44 is a floor, not a look. Every control is at least 44 high on a phone; small-looking links get an invisible hit area.
  2. Gaps inside a card stay small; space between ideas is large. Sections open with the --section clamp, 64 → 112.
  3. Gutters: the portfolio uses --gutter, 16 on a phone to 64 from about 1455; the studio pages use a 14 px frame plus --pad, 20 to 44 (see SG-11). Nothing scrolls sideways at 375.

Detail G · Radii

No shadows: depth is card on ground
22--radius-card · panels176 16--radius-inner · frames, tiles, ad cards 10--radius-control · fields, chips, tags, grades 999Pills, bars, tracks88 50%Dots, rings
  1. Nested radii shrink inward: a 16 tile inside a 22 panel, a 10 image inside a 16 frame. Fields are 10, not pills.
  2. 999 is full round at any height: 44 picks and the top bar pill, 48 buttons, 52 Send and the start button; also progress tracks and table bars.
  3. Drawn 176 wide so every corner reads at 1:1. Tabs take 16 on their top corners and open into a 22 panel. No shadows anywhere: depth is card on ground.

SG-11Phone first, then two widths.

Phone under 700 · tablet 700–999 · desktop 1000 and up · max 1440

Detail J · Breakpoint ruler

Scale 1:1.72 · viewport width, px
NO SIDEWAYS SCROLL · 375 1100 · PORTFOLIO ONLY 560 · ONE USE: NO-ADS STATS MAX WIDTH · --MAXW 1440 PHONE · UNDER 700BASE STYLES, NO QUERY TABLET · 700–999MIN-WIDTH: 700PX DESKTOP · 1000 AND UPMIN-WIDTH: 1000PX WIDTH, PX 0 390 700 768 1000 1440 1600 BASE STYLES = THE PHONE LAYOUT + MIN-WIDTH: 700PX + MIN-WIDTH: 1000PX MAX-WIDTH: 699PX · TABLE FOLDS MAX-WIDTH: 999PX · GRADE ABOVE TABS 64 48 32 16 0 --GUTTER 16 → 64 · 4.4VW · SITE PAGES --PAD 20 → 44 · 3.2VW · STUDIO PAGES 64 FROM 1455 44 FROM 1375 STUDIO FRAME 14 · MAX(14PX, SAFE AREA)
  1. Three widths, two queries. Base styles are the phone; (min-width: 700px) adds the tablet, (min-width: 1000px) the desktop. One off-system query: (min-width: 560px) puts the no-live-ads stats 2-up. The 1100 query is the portfolio header’s only; no studio page uses it.
  2. Mobile-first, two exceptions written downward: (max-width: 699px) folds the category table, (max-width: 999px) lifts the grade chips above the tabs.
  3. Gutters. --gutter (16 up to 364, 64 from 1455; 63.4 at 1440) frames the portfolio’s .container. The studio pages don’t use it: they keep a 14 frame and pad inside with --pad, 20 up to 625, 44 from 1375.
  4. 1440 is the cap. --maxw stops the studio wrap growing; past it the page centres. The 14 frame sits inside the 1440, so content is 1412 at most.

D10 · The studio parts at three widths

Scale 1:3 · widths to scale, heights indicative
Phone · under 700390
Tablet · 700–999768
Desktop · 1000 and up1440
Studio top barUnder 700 the section links are hidden: logo and pill only. From 700 Services · About · Contact show. Nothing changes at 1000.
Snapshot header tiles2-up under 700, 4-up from 700, where each number and its label share a line. From 1000 the button moves beside the headline and lede; the tiles stay 4-up, full width.
Tabs and grade chipsUnder 1000 the grade chips sit above the tabs, centred, and may wrap. From 1000 the tabs are centred and the chips move to the right edge, level with the tabs, on one line.
Category tableUnder 700 the Video, Multi and Image columns are hidden and each brand’s mix moves under its name. From 700 all six columns show. It stays 100% wide: it folds, it never scrolls.

Brand + mix · New · Active

Brand · New · Active · Video · Multi · Image

Same six columns, wider

New-ad cardsNo breakpoint: three columns at every width, the cards shrink (competitors’ newest ads too). The bar under them wraps only when it runs out of room.

Bar wraps to two rows

Bar on one row

Same three, larger

Start pageOne column under 1000: the headline, then the form. From 1000, two columns, 1.05fr | 0.95fr with a 48 gap. The build checklist replaces the form in the same card. What you get: one column under 700, three from 700.

Form card: form, then checklist

Still one column

Headline | form, 1.05 : 0.95, gap 48

  1. StudioBar: nav is display: none, then flex from 700. Padding 16 top and bottom, --pad at the sides.
  2. Tiles: .nums is repeat(2, minmax(0, 1fr)), repeat(4, …) from 700. From 1000 the intro is a two-column grid: tag, tiles, then headline and lede beside the button.
  3. Topbar: under 1000 .grades takes order: -1 so the selected tab still sits on its panel. From 1000 a three-track grid, minmax(0, 1fr) auto minmax(0, 1fr), chips nowrap.
  4. Table: the three format cells .f hide under 700 and the mix line .fm shows in --fs-small; on the brand’s grey row it is ink-3, because mute there is 4.1:1.
  5. New ads: repeat(3, minmax(0, 1fr)) with a 10 gap, no query. The bar is flex-wrap: wrap.
  6. Start: .heroBody goes two-column at 1000; .gets goes 3-up at 700. The checklist card is the same panel slot, shown once the form is sent.

Detail K · Fluid type

Same width scale as Detail J · px at 16 px rem
--fs-h140 → 66 4241188 --fs-h234 → 56 6781289 --fs-h324 → 32 4801280 --fs-lede19 → 22 4401040 --fs-read16 → 17 356911 0 390 700 768 1000 1440 1600
TokenMin → maxMin up toMax fromAt 390At 768At 1440On the studio pages
--fs-h140 → 6642411884051.766Hero headline, studio page and start page
--fs-h234 → 5667812893437.256Page and panel titles, studio page
--fs-h324 → 3248012802426.932Snapshot headline, tile numbers, card titles
--fs-lede19 → 2244010401920.622Intros under a headline; what-you-get titles
--fs-read16 → 1735691116.116.717Field labels, inputs, checklist steps, logo
  1. Each clamp has its own range. None of them runs 375 to 1440: --fs-read is full size from 911, --fs-h2 only from 1289. Past its max width a size is fixed.
  2. No jumps at the breakpoints. Between its two widths a size grows in a straight line with the viewport (rem + vw), so type never steps at 700 or 1000; only layout does.

Note · Rules at every width

Checked at 375, 390, 768, 1280, 1440
  1. Touch targets 44 or more on a phone. The logo, the top bar pill, grade chips, picks, “Preview in the feed”, tabs (50) and the start page’s chips all set min-height: 44px; a link that must look small, like “Not your business?”, gets a transparent ::before hit area. One part falls short: an ad card’s Ad Library link is 32.
  2. No sideways page scroll at 375. The page is a 14 frame and fluid tracks; nothing inside is wider than its column.
  3. Wide things scroll inside their own box, never the page: the AI answers grid (.qcard) and the studio page’s logo strip (.strip) take overflow-x: auto. The category table folds instead, see D10.4.
  4. Grid tracks are minmax(0, 1fr), never a bare 1fr, and text children get min-width: 0. Card rows that wrap use minmax(min(100%, 240px), 1fr), so one card never outgrows a phone.

SG-12Motion that confirms, then gets out of the way.

Three curves · six durations · two working loops · one deck

Detail L · Curves

x: time 0 → 1 · y: progress 0 → 1 · handles dashed
P1 (.2, .7)P2 (.2, 1)1001TIME →PROGRESS →
--ease-outcubic-bezier(.2, .7, .2, 1)Fast start, long soft landing. Everything that moves inside a page: tabs, panels, grade sets, reveals, cards in, the hero deck.
P1 (.25, .8)P2 (.25, 1)1001TIME →PROGRESS →
--ease-page-incubic-bezier(.25, .8, .25, 1)Arrivals that cover the view: the new page fading up, the picture viewer opening.
P1 (.4,0)P2 = P3 (1, 1)1001TIME →PROGRESS →
--ease-page-outcubic-bezier(.4, 0, 1, 1)Departures: slow to leave, then gone. The old page fading out, the picture viewer closing.
P1 = P0 (0, 0)P2 = P3 (1, 1)1001TIME →PROGRESS →
linearcubic-bezier(0, 0, 1, 1)The two working loops only: the checklist spinner and the snapshot record’s chase. Even speed reads as “still going”.

Detail M · Durations

Tokens solid · literals in the code hatched
80TAB ARROW DELAY150--DUR-FAST260--DUR-DIALOG-OUT · PAGE OUT450--DUR500--DUR-DIALOG-IN650DECK OUT_MS700PAGE IN800SPINNER TURN900--DUR-SLOW01002003004005006007008009001000MS
msNameUsed by
150--dur-fastHover fills and borders (buttons, service cards, case-study links), the hero message dots, the old panel’s fade on a tab switch, the tab arrow’s fade
260--dur-dialog-outPicture viewer closing. The old page’s fade-out is the same 260, written as a literal in global.css
450--durTabs, grade sets, the new panel, the start page’s progress card arriving, hero deck cards, hero messages, pending ad pictures fading in
500--dur-dialog-inPicture viewer opening
700page in (literal)The new page fading up
900--dur-slowReveal on scroll

D11 · Dialog open and close

Case-study picture viewer · CaseStudy.astro
OPEN · .LB[OPEN] · 500 · --EASE-PAGE-INViewer opacity 0 → 1500translateY(12) scale(.98) → none500Backdrop opacity, blur 8500 · FADES WITH ITCLOSE · .LB · 260 · --EASE-PAGE-OUTViewer opacity 1 → 0260none → translateY(12) scale(.98)260Backdrop opacity260 · DISPLAY, OVERLAY HELD 260EVERY DIALOG: VIEWER, GRADE CHIPS, AD VIEWER, INDUSTRIESSAME TIMELINE · ONE SHARED CLASS, DIALOG.MOTION (GLOBAL.CSS)010020030040050060070080090010001100MS
  1. @starting-style gives the open its start; overlay and display (allow-discrete) keep the viewer on screen for the 260 it takes to close.
  2. One motion for every dialog: the picture viewer, the grade-chip checks, the ad viewer and the industries dialog all take class="motion" (global.css), so they open and close on this same timeline. Their backdrops keep their own blur (6 or 8 px) and fade with them.

D12 · Meta / AI tab switch

AuditPage.astro · ends at 600
CLICK AT 0 · ALL ON --EASE-OUTOld panel opacity (.leaving)150 · --DUR-FAST150 · LEAVE_MS: PANELS SWAPNew panel in: opacity, Y 4 → 0450 · PANEL-IN, ENDS 600Tab raise, fill, colour, top bar450 · --DURTab arrow opacity150 AFTER 80Tab arrow Y −4 → 0450 AFTER 80Grade sets: opacity, X ±14450 · BOTH SETS, ONE CELL010020030040050060070080090010001100MS
  1. Out, then in. The old audit fades for 150, then the panels swap and the new one fades up 4 px over 450, while the tabs and grades are already moving.
  2. Reduced motion: LEAVE_MS is 0 and the tabs’ transitions are off, so the switch is instant.

D13 · Page to page

global.css · @view-transition, every page
VIEW TRANSITION · BOTH START AT 0Old page opacity 1 → 0260 · --EASE-PAGE-OUTNew page opacity, Y 4 → 0700 · --EASE-PAGE-IN010020030040050060070080090010001100MS
  1. A crossfade, not a slide. Only with prefers-reduced-motion: no-preference; otherwise, and in browsers without cross-page view transitions, a plain load.

D14 · Reveal on scroll

reveal.ts · global.css · [data-reveal]
ON ENTRY · OPACITY 0 → 1, Y 18 → 0 · --EASE-OUTItem 1 · --reveal-delay 0900Item 2 · --reveal-delay 80900 AFTER 80010020030040050060070080090010001100MS
  1. Once, on entry (8% visible, bottom margin −8%), then unobserved. Hidden only under html.js; with reduced motion everything is shown at once. On the studio page: the two examples (0, 80) and the stat strip (60 apart).

D15 · Loops

Progress loops run only while work runs · one decorative loop
Build checklist spinner

The doing step’s 16 px ring, top open, turns 360° every .8s linear infinite. Under reduced motion the global override runs it once in 1 ms: a still ring.

Build progress bar

A 6 px track. Not a CSS animation: a 150 ms timer steps scaleX 12% of the way to the builder’s latest report, creeping 0.05 between reports and held at 95 until the page is ready. It moves the same with reduced motion; the % is the message.

RUNNING · 44%
Snapshot record chase

A yellow arc (18% of the outline) laps the running tag every 1.8s linear infinite, over a fill that shows the %. Reduced motion: no lap, a solid yellow border.

Studio hero ad deck ai-services.astro · desktop only, 1000 and up · the site’s only decorative loop

EVERY 2600 (STEP_MS) · --DUR 450 · --EASE-OUTFront card out: −30, 40, 60; opacity 0450Other five step one place forward450650 · OUT_MS: CARD REPAINTED, MOVED TO THE BACK, NO TRANSITIONBack card fades in (after two frames)4502600 · NEXT SHUFFLE0200400600800100012001400160018002000220024002600MS
  1. Six cards, one shuffle every 2600. The front card leaves down-left and fades; the rest step forward and lighten; at 650 it is repainted with the next ad and slips in at the back.
  2. It stops while the pointer is over it, while Pause is pressed (a 44 px button; it toggles to Play) and while the tab is hidden. With reduced motion it never starts and Pause is hidden.
  3. The hero message beside it runs on its own clock: every 6500 a 450 crossfade, rising 10 px. Pause holds it too; hover doesn’t, and choosing a dot hands it to the visitor for good.
  4. Pending ad frames fill with cubic-bezier(.4, .4, .6, 1), near-even with an eased end, timed by the script to the expected wait; off with reduced motion.

Note · Rules for motion

CLAUDE.md motion rules, as built
  1. Motion reveals, connects and confirms. A tab raises into its panel, a viewer rises over the page, a section arrives as you reach it. Nothing moves for decoration but the deck.
  2. Nothing loops except progress (spinner, chase, bar) while work is running, and the one hero deck with its message.
  3. Reduced motion resets every duration to 1 ms and every delay to 0, with one iteration (global.css). Reveals show at once, page crossfades are off, and dialogs appear and close instantly.
  4. Never information by motion alone. The spinner sits beside its step’s words, the bar beside its %, the chase beside “Running”; a still frame says everything.

SG-06Pills, fields and tabs, in every state.

Default · hover · focus · disabled · error

D1 · Pills and their states

R 999 · focus ring 2, offset 3: accent-ink on light, on-dark on dark
Buy your new ads 4822 Buy 3 ads · $297 Send ✓ Selected44
PartDefaultHoverFocusDisabled
Outlinethe call to action Buy your new ads 1.5 ink · no fill Buy your new ads fills ink, card text 16.12 Buy your new ads + accent-ink ring Never disabled
Rustbuying only Buy 3 ads · $297--accent-ink · white 5.55 Buy 3 ads · $297to --ink · white 16.84 Buy 3 ads · $297+ accent-ink ring Buy these adsnothing picked · ink-3 on hair-2, 5.64
Inkthe quiet yes Send--ink · card text 16.12 Sendto --ink-3 · card text 8.72 Send+ accent-ink ring Never disabled
Togglepick an ad Select ad B31.5 hair-2 · ink text Select ad B3border to ink ✓ Selectedpressed · + ring Full at 3 of 3: taps wait
  1. Outline · 48 high, 22 sides. “Buy your new ads →” at the top and bottom of the snapshot.
  2. Rust is for money only. Its label always states the count and the price: $99 an ad.
  3. Ink is the quiet yes: Send for the follow-up email, Continue after a missing page.
  4. Toggle · 44 high. aria-pressed: “Select ad B3” off, “✓ Selected” on.

D2 · Fields

Website · ZIP · email · R 10
DefaultYour website yourbrand.com52
Focus 2 inkYour website sampleburger.co|
FilledYour website sampleburger.com
Error accent-inkYour website sampleburger

That doesn’t look like a web address. Try it like yourbrand.com (no https:// needed).

Composed The ZIP and the follow-up

Business ZIP code So we compare you with businesses nearby.98117
Want us to follow up? OptionalLeave your email and we’ll write to you about your results. We use it for nothing else.
you@yourbusiness.comSend
Want us to follow up? Optional

Thanks. We’ll write to you@yourbusiness.com about your results.

  1. Field on paper, 52 high, R 10 (--radius-control), 1.5 --hair-2, 17 px text so phones don’t zoom. Label 17/500 above, hint 14 in --mute; the placeholder is --mute too, 5.56:1. Never only a placeholder.
  2. Focus: border to ink plus the accent-ink ring, offset 2. The example clears while you type.
  3. Error: the border and one sentence in accent-ink (5.31 on card) saying what to type. Required is an orange *, and aria-required.

D3 · Tabs

R 16 / 22 · Meta and AI · no shadow
Meta Snapshot50 AI Snapshot44
AMeta ads6 of 6 of our standardSee the checks

Hover, the other tab

Meta SnapshotAI Snapshot
  1. Selected is the paper panel it opens, no rule between and no shadow. A 3 px --accent top border and a 6 px caret mark it, so colour isn’t the only cue.
  2. Other tab sits 6 lower on --hair, Geist 500 15 in ink-3 (6.52:1). Hover: --hair-2, ink (10.42:1).
  3. One line of grade chips sits beside the tabs (D6), at the right edge on desktop. Arrow keys move between tabs.

SG-07Reading the snapshot, part by part.

Checklist · stat tiles · grades · category table

D4 · Build checklist

Ring 16 · stroke 2 · gap 3 · row gap 12
Done green fill

16Reading your website

Working orange arc · %

Pulling your live ads and your competitors’

62%
Waiting gray ring

Writing your snapshot

Missing yellow fill

No Facebook page: comparing you with businesses like yours nearby

Failed accent-ink ring

Facebook page: not found

Building your snapshot

Reading your website

Finding your Facebook page

Pulling your live ads and your competitors’

62%

Writing your snapshot

520 · R 22
  1. One moving thing. Only the working step gets the bar and its percentage (ink-3, 8.72:1). The arc is decoration at 2.87:1; the number is the information.
  2. Shape changes with state: fill, open arc, ring, so colour is never the only cue. Done fills --signal-green inside a 3 px gap, drawn with padding, not a shadow.
  3. Steps change words, not order. A missing page rewrites its row and the snapshot carries on.
  4. Announced as a live region, “Building your snapshot”; the bar is a progressbar with its value.

D5 · Stat tiles

Number, then what it counts · R 16
Default
12active ads
104
Long label · wraps
3days since your newest ad
Zero · mute
0new in the last 30 days
No value
–days since your newest ad
Review · internal
11different messages

Composed Four across in the snapshot header

12active ads
10new in the last 30 days
3days since your newest ad
11different messages
  1. Paper tile, R 16, 18 padding. Geist 300 number at --fs-h3, 32 at 1440; 14 px label 8 below in mute (5.56 on paper). Two across on a phone, four on desktop; the instant snapshot sets number and label on one line from 700 px.
  2. A zero is a finding, not an error. It stays in the row and the headline explains it. No data at all prints an en dash.
  3. Yellow is review only. An untraced number can’t be approved, so this state never reaches a prospect.

D6 · Grade chips

A to F · three lights · R 10
A26GreenInk 14.23:1
BGreenInk 14.23:1
CYellowInk 14.42:1
DRedInk 12.98:1
ERedNot issued
FRedInk 12.98:1
AMeta ads6 of 6 of our standardSee the checks CMeta ads4 of 6 of our standardSee the checks FMeta ads0 of 6 of our standardSee the checks
A

Meta ads (Facebook + Instagram): grade A

6 of 6 of our standard

  • Running Meta ads now

    12 live ads.

  • At least 3 ads in rotation

    You run 12. With 3 or more, there’s always a second message to compare.

  • A new ad in the last 30 days

    10 new in the last 30 days; newest is 3 days old.

Graded against our standard: at least 3 ads in rotation, a new one every 30 days, and AI assistants that can read you and name you. A means every check passes; F, fewer than 40%.

  1. Ink letter on the tint, 1 px border in the light’s colour. 26 square, R 10, Geist 500 15: normal text, so it needs 4.5:1. Ink on the green tint is 14.23:1; white on --signal-green would be 4.25:1, so it is never used.
  2. The chip opens its checks in a dialog (R 22, a 44 close) that states the standard. A passed check’s ✓ is a --signal-green mark; a missed one is an --accent-ink ✕. E is skipped: the scale goes D to F.
  3. Never orange. Orange means action. A grade is only ever green, yellow or red.

D7 · Category table

You against your category

Your category this month

New ads in the last 30 days, and the mix of ads running now.

BrandNew, 30 days ActiveVideoMultiImage
Sample Burger Co. You1012552
Competitor E03012
Competitor J00000

Meta ads grade A–BCD–Fon the same six checks as yours

  1. Your row on --hover, with the YOU tag (mono 11, the floor, R 10). Secondary text in that row is ink-3: mute would be 4.10:1 there.
  2. One bar, 10 high, R 999, scaled to the biggest new-ad count. Ink for you, --hair-2 for the rest; the number sits beside it, so the bar is never the only cue.
  3. Mono 11 heads over a 1 px ink rule; numbers right-aligned and tabular. Phones fold Video · Multi · Image into one line under the name.

SG-08Fixes first, then the ads that make them.

New ads · picker · fix list · offer

D8 · New ad cards and picker

4:5 previews · all three start picked

New ads we made for you

From your own site, photos and lines. Watermarked previews: $99 an ad. All 3 are picked: tap one to leave it out.

Selected
Preview4:5
250200

Image ad, in feed (4:5) and Stories (9:16) sizes

✓ Selected
Answers a fix
Preview4:5

Answers fix 02: Name the dish in the first line.

✓ Selected
Left out
Preview4:5

Image ad, in feed (4:5) and Stories (9:16) sizes

Select ad B3
Making
46%Writing copy

Ad B2

Picker footer Count and price move together

3 picked3 of 3 pickedPreview in the feedBuy 3 ads · $297
1 picked1 of 3 pickedPreview in the feedBuy 1 ad · $99
0 pickedNo ads picked yetPreview in the feedBuy these ads

Don’t like any of these? Tell us what you have in mind and we’ll make custom ads for you. Ask for custom ads →

  1. Caption says why the ad exists: the fix it answers, or its format and sizes. 14 px ink-3.
  2. Left out: the preview goes gray and the toggle returns to outline, “Select ad B3”.
  3. Making: each frame on --hover fills with --accent-tint from the bottom and names the step; the ad appears in place when it’s drawn.
  4. The total follows the picks: $99 an ad, 3 ads $297. At zero the pill reads “Buy these ads” and can’t be pressed.

D9 · Fix list and offer banner

Three fixes · one offer · one cross-sell

Three fixes before the holidays

  1. Lead one ad with a line from your own site. None of your live ads use it yet.

  2. Name the dish in the first line. Put it before the offer, so the food is what people read.

  3. Retire your oldest live ad once a new one runs. Keep three or more in rotation.

44
36

Want to see how another competitor shows up? Our Local AI visibility audit asks up to 10 questions of your own, about the competitors you pick, and shows which businesses AI assistants name and what to change. See Local AI visibility →

  1. Mono 14 number in accent-ink over a 1 px ink rule. Bold the change, then one line of why. Three, never more.
  2. The one filled orange surface. --accent-tint, ink text 13.34:1, straight after the fixes; the rust pill (hover --ink) is the heavy placement of the page’s single action.
  3. Cross-sell under the category table: bold question, plain answer, a link, no second button.
  4. Fix text is the brand’s own data; these three are sample lines for Sample Burger Co.

SG-09Every dead end, its own screen.

What happened · why · one next step

E3 · Dead-end screens

Four ways a snapshot can’t finish
DE-1 · No websiteStart form
290 · R 22
Free snapshot
Your Facebook page’s name Your business name I don’t have a Facebook page either

The Meta snapshot reads your live Facebook and Instagram ads, so it needs a website or a Facebook page.

Get my free snapshot
DE-2 · No Facebook pageChecklist
Building

Reading your website

Facebook page: not found

We couldn’t find your Facebook page.

No problem: we’ll compare you with businesses like yours nearby. If you do have a page, add it and we’ll use it.

facebook.com/yourpageContinue
DE-3 · No live adsSnapshot
Meta Snapshot

Meta ads snapshot for Sample Burger Co.

Your live ads

Your adisn’t here

No live Meta ads right now: nothing in Meta’s public Ad Library for your page at 1:20 PM.

Buy your new ads
DE-4 · Daily limitChecklist
Building

Pulling your live ads and your competitors’

Want more snapshots?

That’s 3 snapshots today from here. Leave your email and we’ll run more for you, or check back tomorrow.

you@yourbusiness.comSend

Anatomy. One sentence on what happened, one on why, one control. The control always moves forward: the other field, carry on without, the new ads, or email.

Reuse. Dead ends are built only from the parts on SG-06 and SG-07: the field, the quiet chip, the failed ring, the empty slot, the inline Send.

Tone. Plain and specific: “We couldn’t find your Facebook page.” No account asked for, and no new ads promised that weren’t made.

SG-10The studio speaks as “we”, and shows its working.

Three rules · say and not

Detail H · Voice

Quotes are the live page’s own lines
Rule 01
We made new ads from your own photos and lines.The offer banner, SG-08 · D9
Say“We”, “the studio”, “RD&D Studio”.NotA personal name, a signature, “Prepared by”.
Rule 02
Leave your email and we’ll write to you about your results. We use it for nothing else.The follow-up field, SG-06 · D2
SayShort, plain sentences a shop owner reads once. Why we ask, next to the ask.NotSuperlatives, urgency, promises about results.
Rule 03
You run 12. With 3 or more, there’s always a second message to compare.The checks dialog, SG-07 · D6
SayNumbers that trace to the ad data, the ad copy or the brand’s own site, with our standard printed beside the grade.NotEstimates, benchmarks, or any price but ours: $99 an ad, 3 ads $297.