The landing page grammar

The page grammar for General Translation landing and marketing pages.

Covers
One rail, bands and hatch spacers, heads with a heading and one lead, the shared Cta with Title Case labels, the two icon tiers, Inter only, the mobile type ladder, the svh and dvh law, the read lines for scroll stories, and the rule that mock layouts and the toolchain prototypes are literal specs.
When to use
When designing, building or reviewing a landing page, a home band, or a pricing, enterprise or careers page.
Also in
Aesthetic
Section 1install-skills.mjs

Install

node scripts/install-skills.mjs gt-landing-pages --project <dir>

Run it from a Prototemplate checkout. It links skills/gt-landing-pages into the project’s .claude/skills and .agents/skills; --copy vendors the folder instead, and --dry-run prints each step first.

Section 2SKILL.md

Instructions

General Translation's marketing pages (the home at generaltranslation.com, pricing, enterprise, careers, contact and the pages beside them) share one grammar: a ruled column with one rail, bands separated by hatch spacers, section heads with a heading and one lead, and one shared button. The code ships from apps/landing in gt-cloud, GT's monorepo. The prototypes and the design canon live in Prototemplate, Kevin's design lab and GT brand hub at prototemplate.com, which is the repository this skill is stored in. The rules come from Kevin's review rounds and from the engine CSS that implements them, and the rules a machine can check are held by a lint that the review checklist names.

Paths are relative to a gt-cloud checkout at origin/main ($GT_CLOUD) or a Prototemplate checkout ($PROTOTEMPLATE). Token values, CSS recipes and breakpoints are in references/engine.md. The component APIs (Cta props, BentoRow and BentoCell props, the full glyph vocabulary) are in gt-components; this skill holds how a page uses them.

The reference

  • Two pages outrank every other example. The Dossier (/d/singularity-dossier in Prototemplate) is the completed direction and the canonical reference application (Kevin, 2026-08-06). The shipped home is generaltranslation.com, rebuilt page for page in Prototemplate under /d/production (the Shipped group in the sidebar).
  • Content comes from production: the copy, the sections and their order as origin/main's page components in gt-cloud render them today. The layout grammar comes from the toolchain prototypes (/d/toolchain and its pages, such as /d/toolchain/enterprise and /d/toolchain/pricing) and the Dossier. After a round that invented product vignettes, Kevin ordered production content restored and kept only the diagrams he had praised (2026-08-11).
  • A mock or a toolchain page given as a spec is copied literally: its composition (what sits left and right, which visual sits in which cell, where the bento heads go), its copy and its formatting. Kevin, 2026-08-04, with the plan images: "here are the literal images of the plans." Kevin, 2026-08-11: "we literally give example copy and formatting and writing and diagrams in toolchain enterprise and pricing pages. so build those." Notes written onto a mock are change orders.
  • Copy fidelity alone fails review. The first full build of the v0 sections (2026-08-04) carried the right copy and drifted from the mock layouts, and only the Locadex isometric survived.
  • Mount the existing diagrams before drawing a new one. In gt-cloud: SentenceWidth (sections/developer), ContextResolve and ReviewWorkspace (sections/context), EdgeGlobe (sections/global), StackTower (sections/fullstack), LocaleTag, DitheredMark (shared), RevealSeam and TranslateWindow (home/sections). In Prototemplate, src/app/d/toolchain/diagrams/ also holds lang/RtlMirror, lang/PluralForms, LocaleRouting, surface/GlossarySurface and tc-stack-iso. New artwork is for new content only, and it sits inside a framed cell.
  • Placeholder quotes and rollout figures carry a PLACEHOLDER mark until production supplies real ones. Nothing unannounced or financial appears on a public surface.
  • Before editing gt-cloud, read $GT_CLOUD/.agents/skills/gt-landing/SKILL.md and its references/design.md. They hold the editing map (home bands in apps/landing/src/components/landing/sections/<slug>/, the hero in home/sections/HomeHero.tsx, the shell in landing/shell/) and the section recipe. This skill does not copy that map.

Where the home rules reach

landing/shell/engine.css scopes the grammar under .toolchain-root. landing/home/v0-pages.css adds the home layer (registration crosses, square surfaces, the hatch spacers, the button hover hold, the light skin and the mobile cut) under .toolchain-root:is(.sgdh-root, .sgoh-root, .sgsh-root, .sgbh-root, .sgph-root), the five home roots of Prototemplate's variant sites. gt-cloud uses only sgdh-root, and it is not limited to the home: the roots of pricing, usage pricing, enterprise, careers, contact, the blog, legal, supported locales, the 404 and the footer mount (SiteFooterMount.tsx) all carry toolchain-root sgdh-root, and those pages import v0-pages.css. The partners page and the report card carry toolchain-root alone. Below, "sgdh-root pages" means that whole set.

Rail and bands

The page is one ruled column. .tc-rail (the column wrapper on the home, pricing, enterprise, careers, contact, blog, legal, supported locales and report card pages, and around the footer in SiteFooterMount.tsx) is min(var(--tc-rail), 100%) wide and draws the column's two lines once with border-inline: 1px solid var(--tc-hair). A border rounds to whole device pixels at any zoom, which a background-filled box does not, so the rail is a border.

  • A band inside the wrapper (<section className='tc-sec v0-<slug>'>) draws no side rails. .tc-sec draws only its bottom rule, and the last section draws none.
  • A full-bleed band (the feature bands .tc-band.tcb, the close band .v0-dep) spans the viewport and draws its own inner pair once, at the column edges, from its -in column. On the home these bands are children of main.tc-rail that break out with margin-inline: calc(50% - 50vw) (fullstack.css, context.css, Deploy.tsx); on Prototemplate's /d/toolchain the band sits at page level. Deploy.tsx is the model: the v0-dep-in column carries w-[min(var(--tc-rail),100%)] border-x border-x-[var(--tc-hair-band)]. The band never adds a pair beside the column.
  • In dark, --tc-hair-band aliases --tc-hair, so the rail runs one color through bands and wrapped sections. Prototemplate's toolchain engine gives light bands a stronger line (--tc-hair-band 0.34 against --tc-hair 0.26), because a line on ink needs more alpha than a line on paper to look equal. In gt-cloud both resolve to --color-border in light, and the sgdh-root light skin restates --tc-hair-band: var(--tc-hair) on its paper bands.
  • The outer pair at plus or minus 10px is retired: .tc-rail::before, .tc-nav-in::before, .tc-band::after, the --tc-rail-outer token and gt-cloud's Rails component were deleted in gt-cloud #5007 (Kevin, 2026-09-28: "make sure there's no rules that lead to two side rails"). gt-landing's App Structure list still names Rails; the export is gone from shell/Bento.tsx. Prototemplate keeps a Rails in src/components/shell/Bento.tsx that draws the single pair for a full-bleed band outside a wrapper.
  • Call the column's lines "the page's rail pair, drawn once". The brand's two-hairline connector is "the doubled line" or "the thread". The words "outer pair", "outer rail" and "doubled rails" fail Prototemplate's retired-rail-vocabulary check.

Hatch spacers

  • Home bands are separated by <div aria-hidden className='v0-hatch' /> in HomePage.tsx. Rows inside one section are separated by .tc-hatch. Both are a clamp(28px, 3.4vw, 40px) strip with a 1px --tc-hair rule on each edge over a 45 degree hatch in --tc-hatch. Under 720px .tc-hatch is 40px and .v0-hatch 36px.
  • The hatch owns both of its edges. The section before it drops its bottom rule (.tc-sec:has(+ .v0-hatch)), and next to a full-bleed band the band's own border stands and the hatch drops that edge.
  • .tc-hatch carries position: relative; z-index: 2, because reveal tweens leave transforms on the framed cards above it and their stacking contexts would paint over its top rule.

Registration crosses

  • On sgdh-root pages, each .tc-rail > .tc-sec::after paints a cross at both bottom corners where the seam meets the rail: 9px arms, 1px thick, hanging 5px past the rail, in --cross-ink (rgba(10, 11, 13, 0.38) light, rgba(255, 255, 255, 0.34) dark). The next section's top corners are the same points, so one pseudo per seam is enough.
  • The full-bleed bands (.tcb, .v0-dep) clip their own pseudos, so the section after a band paints its own top pair with ::before. Bands draw no crosses.
  • The arms reach past the rail, so the page root sets overflow-x: clip. overflow: hidden would make a scroll container and stop the sticky figures further down the page.

The row owns every seam

  • Grids of cells are BentoRow and BentoCell from apps/landing/src/components/landing/shell/Bento.tsx. The row is a grid with gap-px over a --tc-hair background, so the 1px gaps are the seams. Cells have no border props.
  • A framed cell (BentoCell framed, which always adds .is-framed) shows the row's hairline background through a 1px reveal: the framed row sets padding: 1px 0, its sides yield to the rail, and where two framed rows meet only the first keeps its strip. A framed cell without the class collects the gap seam and a border-top, which is a 2px double line.
  • Flush at the rail: where a row meets a line that already exists, the cell sits flush and drops that side's reveal. No reveal runs beside a rail, and no border runs beside a seam.
  • A translucent background under a translucent border composites darker than every other hairline (the self-stack). Clip it with background-clip: padding-box. Two stacked translucent grounds do the same, so cells stay transparent and the row paints the one background.
  • Every structural line runs rail to rail and top to bottom. There are no floating bordered cards and no heads floating in whitespace; a head sits in a ruled tc-head or in the cell's own head zone (.shell-cell-head).
  • On sgdh-root pages, structural surfaces are square: the hero card, the terminal window, framed cell cards and band art mats take border-radius: 0. Controls keep small radii (buttons 6px).

Section heads

A section head is a heading and at most one lead paragraph inside a ruled .tc-head (the Customers wall carries its heading alone). The Locadex band is the model:

<section className='tc-sec v0-ldx' id='locadex' ref={root}>
  <div className='tc-head'>
    <i className='tc-head-icon v0-ldx-head-mark' aria-hidden />
    <T>
      <h2 data-reveal>
        The easiest way to localize <br />
        your full product suite
      </h2>
    </T>
    <T>
      <p data-reveal>
        Connect agents and integrate any content source or tool with{' '}
        <GtLogoText />
      </p>
    </T>
  </div>
  • A head runs at most two lines of display type. A three-line header is the named anti-pattern from the 2026-08-04 review. On sgdh-root pages a head runs one line at desktop (white-space: nowrap from 760px) unless an authored break splits it.
  • A head has no eyebrow: no uppercase tracked line above the heading, no mono label, no kicker that restates the heading. Kevin's word for the stacked version is "3 lines of text stacked to say the same thing" (brand questionnaire, 2026-08-11). Functional layer tags inside a diagram are exempt.
  • The heading has no trailing period. The lead is one or two sentences. Copy follows gt-voice: no em dashes, no metaphors, no paired contrasts.
  • The .tc-head-icon watermark is optional: 240px, 5 percent ink, bleeding 48px off the right edge, hidden under 720px. It is a meaning mark, so it is a Heroicons solid glyph (CodeBracketIcon on Developer, BookOpenIcon on Context, GlobeAltIcon on Global) or a house mark (the Locadex band masks /brand/locadex-mark.svg at 343px).
  • Inside a full-bleed band the head is .tcb-head (sections/shared/darkband.css): the heading and its one line on a shared baseline, nothing else.
  • A two-column band whose copy sits beside its art reuses the tc-head type sizes for its copy block.
  • The engine sets .tc-head padding to clamp(54px, 6.4vw, 82px) var(--tc-gut) clamp(28px, 3.2vw, 38px), the h2 to clamp(1.62rem, 2.5vw, 2.2rem) with a 22ch measure, and the lead to 15px / 1.62 in --tc-ink-2, 13px below the heading and 60ch wide.

Buttons

Every button on a landing page is the shared Cta in apps/landing/src/components/landing/shared/Cta.tsx, over the engine's tc-btn faces (gt-ui/shared-cta refuses tc-btn markup anywhere else). Its props and render forms are listed in gt-components.

  • variant='solid' is the ink face, which flips to white in dark. outline is the hairline face for the second action. on-ink-solid and on-ink-outline are for the horizon heroes (careers, the 404), whose ground is the black-hole field. Those heroes turn to paper in light, and their own sheets (careers.css, not-found.css) re-key the on-ink faces to ink-on-paper there.
  • size is sm 32px, md 38px (the default) or lg 44px. Under 720px the engine raises every button to 44px and sm to 38px.
  • tracked fires PostHog cta_clicked with that location slug.
  • The ring (ring, .tc-cta-ring) marks the page's primary action. On the home it appears twice: the hero's Get Started and the Deploy band's Get Started. A band carries at most one ringed button. The hero's primary goes to the product (the dashboard sign-in), and an in-page jump is the wrong target for it.
  • On sgdh-root pages the solid face keeps its ground on hover in both themes, and the ring's lift is the hover response (v0-pages.css).
  • Labels are Title Case, with short function words lower after the first word: Get Started, Get in Touch, Get a Demo, Talk to Us, Read the Docs, Go Home, Copy Prompt, Setup for Agents. The enterprise hero's Talk to an Engineer was cut on 2026-08-15; the live enterprise page reads Talk to Us (2026-10-06).
  • The PostHog location slugs are frozen. Pass tracked only with a slug that fires today; a new slug changes the analytics contract and needs Kevin's approval.
  • A label that changes state (the hero's Setup for Agents, then Copied or Copy Failed) sizes the face from the idle label through a grid sizer, so the centered row never moves (gt-cloud #5049, 2026-09-30).
  • Gaps beside a glyph are matched by what the eye sees. Lucide glyphs sit differently in their 24-unit boxes (ArrowRight draws from unit 5, Copy from unit 2), so equal CSS gaps give unequal visible gaps. Measure from the label's right edge to the glyph's first drawn column and from its last drawn column to the button edge, and match those numbers across the buttons in a row (Kevin, 2026-10-01).
  • At 620px and below, the hero buttons fill the content column up to 440px wide: side by side at half the row each when both labels fit, otherwise one per row.
  • Prototemplate's /d/production mirror and the directions write tc-btn classes directly, because src/app/d/** sits outside Prototemplate's oxlint scope. Code ported back to gt-cloud goes through Cta.

Icons

Icons come in two tiers, plus brand marks (gt-cloud #4909, 2026-09-24; swept site-wide in #5007, merged 2026-09-29). The tier rules, the full glyph vocabulary and the lint's reach are in gt-components and its references/icons.md.

  • A mark that carries meaning (a card, a feature, a link destination, a section watermark, a status) is Heroicons solid from @heroicons/react/24/solid, sized with a class. A control (search, copy, chevrons, arrows, close, the theme and language switches, menu toggles, loaders) is Lucide outline. Brand marks stay as drawn (GtMark, LocadexMark, framework logos). gt-ui/icon-tiers enforces the split.
  • Reuse the vocabulary before choosing a glyph: Pricing TagIcon, Enterprise BuildingOffice2Icon, Blog NewspaperIcon, Integrations the house PlugIcon, and Locadex always LocadexMark (a brain glyph is wrong).
  • The theme switch is the circle glyphs, ◐ for light and ◑ for dark, from the shared ThemeToggle in packages/ui/src/components/frame/ThemeToggle.tsx, which the landing footer (V0Footer.tsx) and the header mount. The glyphs swap by CSS (dark:hidden, hidden dark:inline). A sun or moon icon is wrong (Kevin, 2026-09-28), even where main still draws one (gt-components lists those files).
  • No robot, bot or sparkle iconography for AI features (questionnaire avoid list, 2026-08-11).
  • Flags come only from LocaleFlag or LocaleTag: no emoji flags, hand-written fi fi-xx classes or flag images (gt-ui/no-raw-locale-flags).
  • To inventory a page, grep from 'lucide-react' under apps/landing/src and packages/ui/src/components and classify each use.

Type on the page

  • Inter is the only typeface on landing pages (Kevin, 2026-09-18: "change switzer to inter everywhere. dont need switzer and remove those files"; gt-cloud #4887). The face is rsms.me's InterVariable v4.1 from apps/landing/public/fonts, declared once in apps/landing/src/lib/fonts.ts as --font-sans; the italic build lives in fonts-prose.ts so only prose routes preload it. Prototemplate loads the same build as --font-inter.
  • Mono comes in two forms. The engine's --tc-mono (Tailwind font-tc-mono) is the system stack ui-monospace, 'SF Mono', Menlo, Consolas, monospace, and band code uses it. Geist Mono, loaded in fonts.ts as --font-mono, is Tailwind's font-mono and the only mono webfont the app loads.
  • --tc-disp resolves to --tc-sans. Keep the slot; it is the grammar's hook for display rules.
  • Weight 500 is the cap for headings at every size. The engine sets h1 to h4 to weight 500, line-height 1.06, letter-spacing -0.028em and margin 0.
  • Mono is for strings that carry numerals: measurements, values, code (Kevin, 2026-08-01). A plain-word caption or label is set in Inter, without uppercase tracking.
  • gt-cloud's gt-ui skill, which gt-landing routes UI work to, describes packages/ui defaults in typography.md: Geist on font-sans, font-semibold headings and text-xs uppercase tracking-widest section labels. None of those hold on a landing page. The landing's --font-sans is Inter, the engine caps headings at 500, and an uppercase tracked label fails gt-ui/no-eyebrow.
  • Prototemplate's own chrome sets its nameplate in Fraunces and Space Grotesk (DESIGN.md sections 4 and 15), which BRAND.md section 6 calls the lab's stationery. A GT landing page uses Inter alone.
  • Heading and paragraph metrics live in engine CSS. The engine's resets are unlayered and Tailwind utilities sit in a layer, so font-semibold, leading-*, tracking-* and margin utilities on h1 to h4 and p lose without a warning. Put those properties in the band's own stylesheet under .toolchain-root, or space siblings with a gap on the flex or grid parent (2026-08-07).
  • The other Tailwind 4 traps (text-[length:var(--x)] for a size, class candidates scanned from comments, unused @theme tokens dropped from the build) are in gt-website. Tailwind classes added to packages/ui may also need touch apps/landing/src/app/globals.css before the landing dev server compiles them.

The mobile ladder

Under 720px, type and spacing come from one token ladder (gt-cloud #4240, 2026-08-08). Kevin's standing directive is that mobile is designed for the phone and never reads as the desktop page shrunk.

  • The --tcm-* slots are declared on .toolchain-root in the engine's late @media (max-width: 720px) block, near the end of engine.css (Prototemplate: src/app/d/toolchain/styles.css). Several base rules sit between the early 720px block and the late one, and a same-specificity override only wins by following them, so new mobile floors go in the late block.
  • Every consumer reads var(--tcm-X, <px fallback>) with the slot's canonical value as the fallback, so a rule outside the ladder's reach degrades to the same number. A new mobile rule never hardcodes a size the ladder has a slot for.
  • The mobile cut in home/v0-pages.css (.toolchain-root:is(.sgdh-root, ...)) has higher specificity than any engine floor. A raise made only in the engine does not render on sgdh-root pages. Change both in the same commit.
  • Copy sits at least 20px from any hairline on mobile: --tc-card-pad drops to 20px under 720px, and the trust lead carries a 20px bottom pad.
  • Tap targets are 44px: .tc-btn is 44px under 720px, and footer links sit on about a 46px pitch.
  • An authored <br /> needs {' '} before it. The mobile cut hides some breaks, and without the space the two words fuse.
  • The mobile hero h1 reserves two lines (min-height: 2.2em), so the morphing headline cycles every locale without moving the layout. Its size is set against the longest of the sixteen sentences: at 390px French tips to a third line at 2.75rem, so the size stays just under it (clamp(2.1rem, 10.9vw, 2.7rem)).

Copy rules that show on the page

  • Rendered copy carries no em dashes (Kevin, 2026-08-11, and the no-em-dash lint).
  • On pricing pages, whole dollars of at least $1 render without cents ($2, $5), and cent prices keep two decimals ($0.50, $1.06). The formatter is packages/ui/src/components/pricing/dollar-format.ts (Kevin, 2026-09-10).
  • Mocks read complete at 390px. A diff, terminal or table mock that would crop gets its own narrow block (the enterprise PR diff mock has a 480px block with 11.5px type and its file path hidden).

Scroll stories

The full-stack band is the model for a story that builds a figure as the reader scrolls (sections/fullstack/FullStack.tsx and fullstack.css in gt-cloud; src/app/d/_v0/sections/ in Prototemplate; DESIGN.md sections 13 and 14).

  • The story keys on two lines with separate jobs. The read line at 55 percent of the viewport is structural: a beat locks in when the center of its copy block crosses it, and the tower's build clock, the capstone scrub and the sticky figure's seat all key on it. The highlight line at 80 percent belongs to the spotlight alone: a beat's copy lights as its center rises through it, while the arriving layer is still building. In code, READ_LINE = 0.55 and HIGHLIGHT_LINE = 0.8.
  • Anchors are measured on the copy itself and from flow geometry. The beat window's top runs about half a viewport ahead of its copy, and anchoring on it made every layer arrive early (Kevin: "each layer arrives too early"). The finale is sticky, so its flow top is the previous beat's bottom; its own rect would read the stuck pose on a refresh mid-dwell. Re-anchor on every ScrollTrigger refresh.
  • One scrubbed dial spans the read. A piecewise map from measured lock-ins to story time holds the clock while a row is being read and spends each gap as hold, build, lock, so a layer stands locked before its copy reaches the read line.
  • The figure is CSS sticky. JavaScript never positions it ("the diagram keeps moving down as i scroll past agents, which is wrong"). The agents beat gets a dwell runway before the native sticky release carries the figure out with the band.
  • At 1020px and below (with at least 500px of height) the band becomes a stage: a CSS-sticky grid that fills the viewport, with the figure in the top 55 percent and one beat's copy in the bottom 45 percent (grid-template-rows: minmax(0, 11fr) minmax(0, 9fr)). The tower's width budget --v0sm-tw uses the same 0.55 factor, so the split and the factor change together; short windows (500 to 639px tall) rebalance both to 0.5. One ScrollTrigger over the .v0sm-runway spacer after the grid is the story clock. The stage's bullets stay 15px / 1.5 because the longest beat must fit the text zone.
  • The svh and dvh law sets every stage height. Reach is dvh: whatever must touch the true screen bottom (the stage's rails, the text zone) sizes from 100dvh. Layout is svh: any height that takes part in layout uses 100svh, because a dvh layout height grows the document on every browser chrome toggle and the scroll jitters. The difference is the token --v0sm-bar-gap (--v0sm-stage-h minus --v0sm-stage-h-stable, 0 while the URL bar shows), and only overhangs spend it. Anything sized from the stage derives from the stable var.
  • Every loop is created paused and plays only while its band is on screen. Under prefers-reduced-motion the setup is skipped and the markup pose is the still: the full stack with the first beat lit and the mark's shimmer parked.
  • Scrolling is native. shared/SmoothScroll.tsx is a pass-through kept as a mount point; no Lenis or Locomotive, no scroll-smooth, no behavior: 'smooth', and in-page links jump. Prototemplate exempts only /present, the presenter.

Material

  • The hero's field is the studio field: shared/HeroField.tsx calls createStudioField(canvas, { preset: 'bayer8' }) from apps/landing/src/lib/studio-field.ts, through one shared GL context. The engine owns the frame loop, resizing and the reduced-motion still, so destroy() is the only cleanup.
  • The glyph fields come from packages/ui/src/lib/glyph-field.ts (imported as @generaltranslation/ui/lib/glyph-field), shared since 2026-08-13: the Deploy band's condensation field, the pricing close, the careers rain (shared/GlyphRain.tsx) and the enterprise contact bay (through glyph-rain/sections/band/inkField.ts). Import the shared engine; app-local copies are not allowed to come back. Its design contract (matter is conserved and the word comes first) is in gt-motion and gt-dither.
  • Density ramps use ordered dither from packages/ui/src/lib/dither.ts and DitheredMark (DESIGN.md section 7). An alpha veil does not count as a ramp.
  • New decorative material starts in Glyphfield (glyphfield.com/studio), following gt-cloud's glyphfield skill. Copy and buttons stay page content and are never baked into the artwork.
  • Marks are drawn: an SVG, a canvas field, LocadexMark. A gif is never a mark or a demo frame (Kevin, 2026-08-04: Locadex is never a gif). A mark seated in an isometric face is an alpha mask (gt-isometric).
  • A page spends one accent, --tc-accent: #2f5ce0; light paper is one white; the one black is the house background; --tc-panel is the one dark surface for code, config and diffs. Dark mode is a token remap under [data-theme='dark'] .toolchain-root and nothing else. Components take colors from the tokens (no-hex-colors checks className and style values). A literal color lives in a stylesheet, such as the ring's gradient and the on-ink faces in engine.css, and never in a className or style prop.
  • Light mode has no black backgrounds. On sgdh-root pages v0-pages.css moves the .tc-band.tcb feature bands onto paper and turns the panel family into white plates read by their rules (--tc-panel: #ffffff, its inks re-bound to black alphas). The Deploy close becomes a white day plate that keeps its ring (deploy.css), and the careers and 404 heroes turn to paper with only the black-hole disc keeping its black. A comment in v0-pages.css still names Deploy as the one exception; deploy.css overrides it.
  • Avoid AI gradients ("ugly ai gradients", the blog round of 2026-08-11), glassmorphism, rainbow washes as decoration, flag soup and robot iconography.

Process

  • Work exemplar first: rebuild one section, get Kevin's sign-off on the grammar, then replicate. A full-fleet rebuild on an unconfirmed reading is the failure of 2026-08-04.
  • Never iterate on a version Kevin rejected. Restart from the spec, the production content and the praised pieces.
  • Explorations stay local. Prototemplate rounds are reviewed on localhost:3005 before anything reaches main, and landing a round is Kevin's call each time (2026-09-14). gt-cloud work goes up as a pull request with screenshots in its body (gt-ship).
  • A visual standard ships to every surface that shows it, through packages/ui, in one sweep: landing, docs, dashboard, sign-in and admin. Unrelated redesigns stay out of a sweep pull request, so an objection to one does not hold up the other.
  • Contrast meets AA. Dim text on the panel is at least 0.5 white on the ink panel and 0.58 black where the light skin turns the panel white (--tc-panel-dim). In the language diagrams, --lang-low (a 62 percent mix of currentColor, shared/lang.css) is the quietest tone real text may take. The full-stack tower's cold beats at opacity 0.38 fail AA on purpose as spotlight de-emphasis (2026-08-07); raising them needs Kevin's call.
  • Audit every page at five widths (390, 768, 1024, 1440, 1920) in both themes. Take element-level screenshots for review, and check rail and seam work at 2x pixel crops of the junctions; a full-page shot hides a doubled line.
  • A port is verified with reduced-motion screenshots and a pixel diff to 0.00 percent. The footer's metal-mark canvas is the one known source of noise (about 0.8 percent).
  • Two Prototemplate tools check a page. node scripts/lint-lines.mjs <url> --theme dark audits any page at 1440 and 1280 for doubled lines, missing seams and junctions, gt-cloud's landing dev server included. pnpm check:pages reads overflow, clipped text, tap targets and layout shift at ten viewports in both themes; --base and --pages-module point it at another site (scripts/pagecheck/README.md). Both drive Playwright's Chrome for Testing: the page check reads its path from CHROME_PATH, and lint-lines.mjs hardcodes it in EXEC near the top of the script, so edit that line on another machine.

Review checklist

  • [ ] Content matches production, or the toolchain page or mock it was specified from, and nothing is invented.
  • [ ] The layout reproduces the spec's composition, with existing diagrams mounted.
  • [ ] One rail: no band inside .tc-rail draws side rails, a full-bleed band draws its inner pair once from its -in column, and nothing draws a second pair beside the column (gt-ui/single-rail, lint-practices rail checks).
  • [ ] Bands are separated by v0-hatch or .tc-hatch, and the neighbors yield the hatch's edges.
  • [ ] Grids are BentoRow and BentoCell; no cell draws a border along a row seam; framed cells carry .is-framed.
  • [ ] No translucent background sits under a translucent border, and no two translucent grounds stack.
  • [ ] lint-lines.mjs reports no doubled lines or junctions in either theme, and 2x crops of the junctions agree.
  • [ ] Every head is a heading and at most one lead in a ruled box, at most two lines of display type, with no eyebrow, mono or uppercase tracking (gt-ui/no-eyebrow, gt-ui/mono-is-not-voice) and no heading period (gt-ui/no-heading-period).
  • [ ] Every button is Cta (gt-ui/shared-cta), labels are Title Case (gt-ui/cta-title-case), the ring marks the primary action only, and no new tracked slug was added.
  • [ ] Meaning marks are Heroicons solid, controls are Lucide outline, brand marks are untouched (gt-ui/icon-tiers), and the theme switch draws ◐ and ◑.
  • [ ] Inter is the only face (gt-ui/inter-only), weights stay at 500 or below, heading or paragraph metrics live in engine or band CSS, and none of gt-ui's Geist, semibold or uppercase-label defaults reached the page.
  • [ ] Mobile rules consume var(--tcm-*, <px>), sit in the late 720px block, and the v0-pages mobile cut moved with them.
  • [ ] In light, no band, panel or close sits on a black background.
  • [ ] At 390px: copy is 20px or more from every hairline, tap targets are 44px, no mock crops, no words fuse at a hidden break, and nothing scrolls sideways.
  • [ ] Scroll stories key structure on the 55 percent line and the spotlight on the 80 percent line, the figure is CSS sticky, layout heights use svh and reach uses dvh.
  • [ ] Scrolling is native (gt-ui/no-smooth-scroll), there are no gifs (gt-ui/no-gif-mark), and no hex colors outside the sanctioned files (gt-ui/no-hex-colors).
  • [ ] No em dashes in copy (gt-ui/no-em-dash), and money follows the whole-dollar rule.
  • [ ] Reduced motion renders a complete still, and loops pause off screen.
  • [ ] Contrast passes AA in both themes.
  • [ ] Checked at 390, 768, 1024, 1440 and 1920 in light and dark.
  • [ ] gt-cloud: pnpm lint from the repository root passes (scripts/check-email-identities.mjs, which refuses GT email addresses written outside packages/settings/src/email.ts, then oxlint with the gt-ui plugin, then oxfmt --check .). Prototemplate: pnpm lint:all passes.

Related skills: in this set, gt-website (the app around the pages: routes, translation, deploys, the Tailwind traps), gt-voice (the copy), gt-aesthetic (the taste bar and polish), gt-lints (the gt-ui plugin and Prototemplate's lints), gt-components (the Cta and Bento APIs, the glyph vocabulary, shared UI), gt-motion (GSAP discipline and the moving type), gt-dither (studio and glyph fields), gt-isometric (the iso kit and seated marks), gt-diagrams (the doubled line), gt-ship (pull requests and screenshots). In the wiki: agent-browser (screenshots and the audit), design-engineering-polish (the final pass), animated-component-libraries (sourcing a component before hand-building one). In gt-cloud: .agents/skills/gt-landing, gt-ui, glyphfield, react-useeffect.

Sources

  • Prototemplate: DESIGN.md sections 1 (the four colors), 2 (the line law and its ownership rules), 3 (the rails), 4 and 15 (the nameplate's faces), 7 (the 1-bit language), 9 (motion discipline), 12 (the mobile type ladder and the box-air standard), 13 (the svh and dvh law), 14 (the two read lines); BRAND.md section 6 (type).
  • Prototemplate: ARCHITECTURE.md (the SSOT rule, the componentized instruments); src/lib/directions.ts (the singularity-dossier and production entries).
  • Prototemplate: src/app/d/toolchain/styles.css (tokens, the heading reset, .tc-hatch, the late 720px block); src/app/d/_v0/v0-pages.css (the home's mobile cut); src/app/d/_v0/sections/FullStack.tsx and fullstack.css (the read lines, the stage tokens); src/components/shell/Bento.tsx.
  • Prototemplate: .oxlintrc.json (the gt-ui rules over the live surfaces); scripts/lint-practices.mjs (outer-rail-pair, rail-outer-token, retired-rail-vocabulary); scripts/lint-lines.mjs; scripts/pagecheck/README.md and scripts/site-pages.mjs (CHROME_PATH); src/components/shared/SmoothScroll.tsx.
  • gt-cloud: .agents/skills/gt-landing/SKILL.md and references/design.md (the editing map and the section recipe; rewritten 2026-09-18 in #4886, icon tiers added in #4909, rail and lints in #5007); .agents/skills/gt-ui/typography.md (the packages/ui defaults the landing overrides).
  • gt-cloud: apps/landing/src/components/landing/shared/Cta.tsx; landing/shell/engine.css (tokens, .tc-rail, .tc-head, .tc-btn faces, .tc-cta-ring, the framed row, the 620px hero cut, the late 720px block, the dark remap); landing/shell/Bento.tsx; landing/shell/SiteFooterMount.tsx; landing/home/v0-pages.css (the five home roots, crosses, v0-hatch, square surfaces, the hover hold, the light skin, the mobile cut); landing/sections/shared/darkband.css (.tcb-in, .tcb-head); landing/shared/lang.css (--lang-low).
  • gt-cloud: landing/sections/locadex/Locadex.tsx and locadex.css (the head example, the masked mark); landing/sections/developer/Developer.tsx, context/ContextSec.tsx, global/Global.tsx, customers/Customers.tsx (the other heads); landing/sections/deploy/Deploy.tsx and deploy.css (the full-bleed inner pair, the ringed close, the light day plate); pages/careers/careers.css and pages/not-found/not-found.css (the horizon heroes in light); landing/sections/fullstack/FullStack.tsx and fullstack.css; landing/home/sections/HomeHero.tsx; landing/shared/HeroField.tsx and GlyphRain.tsx; apps/landing/src/lib/fonts.ts and fonts-prose.ts; apps/landing/src/app/globals.css; apps/landing/src/components/pages/home/HomePage.tsx; the className roots of apps/landing/src/components/pages/* and the root package.json (lint).
  • gt-cloud: tooling/oxlint-plugins/gt-ui.ts and .oxlintrc.json (single-rail, shared-cta, cta-title-case, no-eyebrow, icon-tiers, inter-only, mono-is-not-voice, no-smooth-scroll, no-gif-mark, no-em-dash, no-heading-period, no-hex-colors, typed-text-var, no-raw-locale-flags); packages/ui/src/components/frame/ThemeToggle.tsx; packages/ui/src/components/pricing/dollar-format.ts; packages/ui/src/lib/glyph-field.ts.
  • Claude Code project memory for gt-cloud: landing-cta-conventions.md, landing-icon-rule.md, landing-inter-only.md, mobile-type-ladder.md, redesign-v0-verdict.md, k-pages-restart-round.md, redesign-fork-architecture.md, tailwind-port-conventions.md, responsive-audit-round.md, lighthouse-round-conventions.md, dossier-completed-brand-canon.md, brand-questionnaire-directives.md, shared-ui-standardization.md, explorations-stay-local.md, landing-hero-agent-button.md, landing-ai-gateway-faq.md.
  • Kevin, 2026-07-31 (one white, the line law, rail ownership); 2026-08-01 (mono is for numbers); 2026-08-04 (the v0 verdict: mocks are literal, two-line heads, exemplar first); 2026-08-06 (the Dossier is the completed direction); 2026-08-07 (the hover hold, the unlayered engine, the contrast floors); 2026-08-08 (the mobile ladder); 2026-08-11 (production content, the toolchain pages as the spec, the questionnaire's avoid list); 2026-08-14 (the shared Cta, the responsive audit); 2026-09-10 (whole dollars); 2026-09-14 (explorations stay local); 2026-09-18 (Inter only); 2026-09-24 and 2026-09-28 (icon tiers, the eleven grammar lints, one rail); 2026-09-30 (one rail in Prototemplate, Setup for Agents); 2026-10-01 (glyph gaps by drawn columns).
Section 32 files

Files

The folder skills/gt-landing-pages as agents fetch it. Each file opens raw.