The page grammar for General Translation landing and marketing pages.
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.
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.
/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)./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).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.$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.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.
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.
<section className='tc-sec v0-<slug>'>) draws no side rails. .tc-sec draws only its bottom rule, and the last section draws none..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.--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..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.retired-rail-vocabulary check.<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..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.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..tcb, .v0-dep) clip their own pseudos, so the section after a band paints its own top pair with ::before. Bands draw no crosses.overflow-x: clip. overflow: hidden would make a scroll container and stop the sticky figures further down the page.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.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.background-clip: padding-box. Two stacked translucent grounds do the same, so cells stay transparent and the row paints the one background.tc-head or in the cell's own head zone (.shell-cell-head).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).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>sgdh-root pages a head runs one line at desktop (white-space: nowrap from 760px) unless an authored break splits it..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)..tcb-head (sections/shared/darkband.css): the heading and its one line on a shared baseline, nothing else.tc-head type sizes for its copy block..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.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.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.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).tracked only with a slug that fires today; a new slug changes the analytics contract and needs Kevin's approval./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 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.
@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.TagIcon, Enterprise BuildingOffice2Icon, Blog NewspaperIcon, Integrations the house PlugIcon, and Locadex always LocadexMark (a brain glyph is wrong).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).LocaleFlag or LocaleTag: no emoji flags, hand-written fi fi-xx classes or flag images (gt-ui/no-raw-locale-flags).from 'lucide-react' under apps/landing/src and packages/ui/src/components and classify each use.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.--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.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.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).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.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.
--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.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.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.--tc-card-pad drops to 20px under 720px, and the trust lead carries a 20px bottom pad..tc-btn is 44px under 720px, and footer links sit on about a 46px pitch.<br /> needs {' '} before it. The mobile cut hides some breaks, and without the space the two words fuse.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)).no-em-dash lint).packages/ui/src/components/pricing/dollar-format.ts (Kevin, 2026-09-10).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).
READ_LINE = 0.55 and HIGHLIGHT_LINE = 0.8.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.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.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.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.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.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.packages/ui/src/lib/dither.ts and DitheredMark (DESIGN.md section 7). An alpha veil does not count as a ramp.glyphfield skill. Copy and buttons stay page content and are never baked into the artwork.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).--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.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.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.--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.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..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).v0-hatch or .tc-hatch, and the neighbors yield the hatch's edges.BentoRow and BentoCell; no cell draws a border along a row seam; framed cells carry .is-framed.lint-lines.mjs reports no doubled lines or junctions in either theme, and 2x crops of the junctions agree.gt-ui/no-eyebrow, gt-ui/mono-is-not-voice) and no heading period (gt-ui/no-heading-period).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.gt-ui/icon-tiers), and the theme switch draws ◐ and ◑.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.var(--tcm-*, <px>), sit in the late 720px block, and the v0-pages mobile cut moved with them.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).gt-ui/no-em-dash), and money follows the whole-dollar rule.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.
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).ARCHITECTURE.md (the SSOT rule, the componentized instruments); src/lib/directions.ts (the singularity-dossier and production entries).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..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..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).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).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).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.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.The folder skills/gt-landing-pages as agents fetch it. Each file opens raw.
SKILL.mdreferences/engine.md