Skip to content

Now in the official shadcn registry directory.

Start free
Back to gallery
saas · developer tools

Plain

Restraint as a reaction to every bad support tool — teal accent, dark-green canvas, ABC Favorit + Geist Mono. Customer support in Linear's discipline.

plain.comAdded 2026-06-23
Plain - Desktop

Editorial disclaimer

Editorial note

This entry documents observable design-language patterns for educational transfer and AI-agent briefing. Screenshots and trademarks are property of their respective owners. AI2 Design is not affiliated with or endorsed by the featured brand. Inspiration here is about language and rhythm - do not reproduce brand identity, logo, product copy, or proprietary features.

Fair Use & Gallery Policy
FreePrompt kit

Copy the full design language into your agent

A typed, paste-ready design system brief - philosophy, tokens, rules, techniques, and fitness checks. Drop it into Claude, Cursor, v0 or any coding agent and it builds in Plain’s language, not just a screenshot.

Paste into your agent. No signup, no cost.
Calm operational minimalism carried by a single humanist sans. The canvas is off-white (#f3fbe9) over a deep green-black (#0a2414); ABC Favorit (Regular 400 / Medium 500) carries voice, weight, and rhythm across heading and body alike, with Geist Mono reserved exclusively for tiny eyebrow labels (13px, +0.195px tracking). Display headings step down a wide editorial ladder (80 / 48 / 44 / 24px) with negative px tracking (-1.6 to -0.48px) so type feels bound. A single brand teal (#17b267) and the classic link blue (#0000ee) are the only accents — color as punctuation, never paint. Elevation is delivered through near-invisible multi-layer shadows; motion is one curve at one duration, applied everywhere. Discipline over decoration, coherence over choreography.
Main prompt
Use this capture as a design language transfer brief for my project. Adopt the palette (off-white #f3fbe9 foreground on a deep green-black #0a2414 canvas, with a single brand teal #17b267 accent and classic blue #0000ee for inline links), the single-family typographic system (ABC Favorit Regular/Medium across heading and body, Geist Mono only for tiny mono eyebrow labels), the editorial heading ladder with negative px tracking (80/48/44/24px), the calm spacing scale (4/8/10/12/16/20/24/40/62px on a 1200px bounded container), whisper-quiet multi-layer elevation, the granular radius ladder (6/8/9/10/12px), and the single-curve motion language (cubic-bezier(0.44, 0, 0.56, 1) at 0.4s) across every page and component I ship. Treat this as my project's constitution — any new component I author should pass as if crafted in the same studio. Apply the language, not the source brand's specific copy or identity. When I ask you to build a page or component, enforce these rules by default, and call out any decision that deviates.
Layout
Editorial
Content width
Bounded
Framing
Flat
Grid strength
Soft

Near-monochrome calm canvas — off-white foreground #f3fbe9 reading over a deep green-black #0a2414 background does ~95% of the surface work, with pure #000000 and #ffffff appearing in component-level contexts. A single brand teal #17b267 carries every accent, emphasis, and call-to-action; the classic link blue #0000ee is reserved for inline anchor text. Semantic red #e23c3c handles error/destructive state only. Accents stay punctuation, never fill.

Mode strategydual-paired
  • Off-white #f3fbe9 foreground (ABC Favorit 400) is the dominant reading layer over the #0a2414 green-black canvas — pairing maintains 4.5+ contrast for body text
  • Brand teal #17b267 (measured 191 occurrences) is the only emphasis accent — buttons, key links, highlighted figures. Keep its surface area under ~5%
  • Classic link blue #0000ee (157 occurrences) reserved for inline anchor text within prose — the browser-default-leaning hue is intentional, signaling 'real link, not decorated button'
  • Pure neutrals #000000 / #ffffff appear in card/panel contexts and inverted surfaces; the off-white #f3fbe9 and green-black #0a2414 remain the brand pairing
  • Semantic red #e23c3c (11 occurrences) is reserved for error and destructive state — never decorative
  • Pink #ffbac3 appears only inside an atmospheric conic gradient accent, never as a fill or text color

Gradients (paste-ready)

radial-gradient(50% 50%, rgba(10, 36, 20, 0.5) 0%, rgb(10, 36, 20) 100%)
linear-gradient(rgba(10, 36, 20, 0) 20%, rgb(10, 36, 20) 100%)
conic-gradient(rgba(255, 186, 195, 0.83) 182.489deg, rgba(255, 186, 195, 0) 339.654deg, rgba(255, 186, 195, 0.83) 360deg)
  • Primary family: ABC Favorit (self-hosted woff2). Two weights only: Regular (400) for reading + Medium (500) for UI labels and emphasis. Monospace: Geist Mono, reserved exclusively for tiny eyebrow/kicker labels.
  • Weight ladder is strictly 400 / 500 — do not introduce 600 or 700. Emphasis is carried by the 500 Medium step and by size, never by a heavier cut.
  • Display tracking is negative and in px, not em: -1.6px on the 80px hero, -0.96px on 48px headings, -0.48px on 24px headings, -0.18px on 18px body. Tracking tightens as size grows — a constant optical correction.
  • Heading ladder (observable): 80px/76px hero (ABC Favorit Regular), 48px/50px section heading, 44px/52.8px display, 24px/28px subhead (Regular or Medium 500). Body reads at 18px/24px and 15px/20px.
  • Mono eyebrow labels: Geist Mono 13px, weight 500, line-height 19px, letter-spacing +0.195px — the only positive tracking on the page, and the only place mono appears.
  • No italic for emphasis — the 500 Medium weight carries it. No second display or serif face; the entire authority is single-family.
  • Paragraph measure stays comfortable at body 18px inside the narrow content rails (360–792px); never let prose run the full 1200px container width.
  • Base rhythm is a 4px grid. Observed scale: 4 / 8 / 10 / 12 / 16 / 20 / 24 / 30 / 33 / 40 / 60 / 62px — calm and generous, not micro-dense.
  • Container max-width 1200px (the dominant bounded rail, frequency 24). Narrow content rails nest inside at 360 / 480 / 592 / 680 / 792px for prose and form clusters.
  • Flex/grid gutters draw from 4 / 8 / 10 / 12 / 16 / 20 / 24 / 40 / 62px — the 10 and 20 gaps are the most frequent (card rows, feature grids).
  • Section vertical rhythm leans on the larger tokens (40 / 60 / 62px) between major blocks; tighter 16–24px inside cards and content clusters.
  • Card padding lands in the 16–24px range on desktop; pull from the scale, never invent magic numbers.
Surface styleFlat
  • Elevation is whisper-quiet: multi-layer shadows at 4–18% alpha with sub-pixel-to-low offsets. Surfaces register as edges, not as floating cards.
  • The signature lifted surface stacks three layers (e.g. `rgba(0,0,0,0.18) 0 0.66px 0.66px -1.25px, rgba(0,0,0,0.16) 0 2.52px 2.52px -2.5px, rgba(0,0,0,0.06) 0 11px 11px -3.75px`) with negative spread so the bloom is tight, never a halo.
  • Default cards use a single near-invisible tint shadow (`rgba(32,39,44,0.04) 0 1.37px 2.66px 0`) — closer to a hairline than a drop-shadow.
  • Depth is communicated through the off-white-vs-canvas background shift far more than through shadow stacking.

Techniques

Three-layer whisper shadow

Primary lifted surfaces use a stacked shadow `rgba(0,0,0,0.18) 0px 0.662406px 0.662406px -1.25px, rgba(0,0,0,0.16) 0px 2.51739px 2.51739px -2.5px, rgba(0,0,0,0.06) 0px 11px 11px -3.75px`. Negative spread on each layer keeps the falloff tight; total visible opacity reads under ~18%. Never increase alpha to 'make it pop' — the point is that it barely does.

Hairline tint shadow

Resting cards and inputs use a single `rgba(32, 39, 44, 0.04) 0px 1.37px 2.66038px 0px` — a 4%-alpha tint that behaves like a soft 1px edge rather than elevation. Pair with a 6–9px radius for the default surface.

Radii6 / 8 / 9 / 10 / 12Icon treatmentLinearIcon setsLucide, Phosphor, Remix Icon
  • Radius ladder is granular and small: 6 / 8 / 9 / 10 / 12px (the captured 12.28px rounds to 12). The 6px and 9px steps are the most frequent — buttons and cards.
  • Buttons and inputs default to 6–9px; cards and panels to 9–12px. No large pill radii except for indicator chips.
  • Icons are stroke-based at 1.5–2px weight; no filled or duotone variants — they should read as quietly as the type.
  • Tap targets minimum 40×40px on pointer, 44×44 on touch.
  • button-primary
    backgroundColor
    #17b267
    textColor
    #f3fbe9
    radius
    9px
    padding
    10px 20px
    border
    1px solid transparent
    boxShadow
    rgba(32, 39, 44, 0.04) 0px 1.37px 2.66038px 0px
    fontFamily
    ABC Favorit Medium
    fontWeight
    500
    fontSize
    15px
    lineHeight
    20px
    letterSpacing
    -0.15px

    Tailwind

    inline-flex min-h-[40px] items-center gap-2 rounded-[9px] bg-[#17b267] px-5 py-2.5 text-[15px] font-medium leading-5 tracking-[-0.15px] text-[#f3fbe9] shadow-[rgba(32,39,44,0.04)_0px_1.37px_2.66038px_0px] transition-colors duration-[400ms] ease-[cubic-bezier(0.44,0,0.56,1)] hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#17b267] focus-visible:ring-offset-2
  • button-secondary
    backgroundColor
    transparent
    textColor
    #f3fbe9
    radius
    9px
    padding
    10px 20px
    border
    1px solid rgba(243, 251, 233, 0.16)
    boxShadow
    none
    fontFamily
    ABC Favorit Medium
    fontWeight
    500
    fontSize
    15px
    lineHeight
    20px
    letterSpacing
    -0.15px

    Tailwind

    inline-flex min-h-[40px] items-center gap-2 rounded-[9px] border border-[rgba(243,251,233,0.16)] bg-transparent px-5 py-2.5 text-[15px] font-medium leading-5 tracking-[-0.15px] text-[#f3fbe9] transition-colors duration-[400ms] ease-[cubic-bezier(0.44,0,0.56,1)] hover:border-[rgba(243,251,233,0.32)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#17b267]
  • card-surface
    backgroundColor
    #ffffff
    textColor
    #000000
    radius
    12px
    padding
    24px
    border
    none
    boxShadow
    rgba(0, 0, 0, 0.18) 0px 0.662406px 0.662406px -1.25px, rgba(0, 0, 0, 0.16) 0px 2.51739px 2.51739px -2.5px, rgba(0, 0, 0, 0.06) 0px 11px 11px -3.75px

    Tailwind

    rounded-[12px] bg-white p-6 text-black shadow-[rgba(0,0,0,0.18)_0px_0.662406px_0.662406px_-1.25px,rgba(0,0,0,0.16)_0px_2.51739px_2.51739px_-2.5px,rgba(0,0,0,0.06)_0px_11px_11px_-3.75px] transition-shadow duration-[400ms] ease-[cubic-bezier(0.44,0,0.56,1)]
  • input-field
    backgroundColor
    #ffffff
    textColor
    #000000
    radius
    6px
    padding
    10px 12px
    border
    1px solid #e3e3eb
    boxShadow
    rgba(32, 39, 44, 0.04) 0px 1.37px 2.66038px 0px
    fontFamily
    ABC Favorit Regular
    fontWeight
    400
    fontSize
    15px
    lineHeight
    20px
    letterSpacing
    -0.15px

    Tailwind

    w-full rounded-[6px] border border-[#e3e3eb] bg-white px-3 py-2.5 text-[15px] leading-5 tracking-[-0.15px] text-black shadow-[rgba(32,39,44,0.04)_0px_1.37px_2.66038px_0px] placeholder:text-[#6e6e7a] transition-colors duration-[400ms] ease-[cubic-bezier(0.44,0,0.56,1)] focus-visible:outline-none focus-visible:border-[#17b267] focus-visible:ring-2 focus-visible:ring-[#17b267]/30
  • eyebrow-label
    color
    #17b267
    fontFamily
    Geist Mono
    fontWeight
    500
    fontSize
    13px
    lineHeight
    19px
    letterSpacing
    0.195px
    textTransform
    uppercase

    Tailwind

    font-mono text-[13px] font-medium uppercase leading-[19px] tracking-[0.195px] text-[#17b267]
  • link-inline
    color
    #0000ee
    textDecoration
    underline
    textDecorationColor
    #0000ee
    textDecorationThickness
    1px
    textUnderlineOffset
    2px
    transition
    color 400ms cubic-bezier(0.44, 0, 0.56, 1)

    Tailwind

    text-[#0000ee] underline decoration-[#0000ee] decoration-[1px] underline-offset-2 transition-colors duration-[400ms] ease-[cubic-bezier(0.44,0,0.56,1)] hover:text-[#17b267] hover:decoration-[#17b267] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#17b267]
LevelsubtleDurations0.4s

Easings

cubic-bezier(0.44, 0, 0.56, 1)
Hovercolor shift (0.4s on cubic-bezier(0.44, 0, 0.56, 1)) — the single observed transition property, opacity fade on primary buttons (0.4s on cubic-bezier(0.44, 0, 0.56, 1)), border-color shift on secondary/outline controls (0.4s on cubic-bezier(0.44, 0, 0.56, 1))

Scroll patterns

  • Framer Motion intersection-triggered opacity + translateY reveals on the single 0.4s curve
  • Stagger groups gently (40–80ms) but keep the per-item curve and duration constant — coherence over choreography
  • No parallax, no long ambient loops — the page holds to one timing idea throughout
  • Single easing: cubic-bezier(0.44, 0, 0.56, 1) — a symmetric ease-in-out that anchors every transition observed (28 occurrences, the only curve captured).
  • Single duration: 0.4s. Do not invent a faster micro-duration or a slower ambient tier — uniformity is the signature.
  • `color` is the primary animated property in the capture; extend the same curve/duration to opacity and border-color for hover, and to opacity+transform for scroll reveals.
  • Framer Motion is the runtime (evidence: window.MotionIsMounted). Use deterministic tweens with the captured curve — no spring physics.
  • useReducedMotion mandatory: all animations collapse to opacity-only or disable.
  • No loop animations except explicit loaders (the only animation observed is a framer loading spinner).
  • Primary CTA is a solid teal button; secondary actions are outline/ghost — never two solid accents competing in the same view.
  • Inline links within prose use the classic blue (#0000ee) underline treatment; navigational/button affordances use teal. The two never blur.
  • Mono eyebrow labels (Geist Mono, uppercase, 13px) introduce sections — the page's only kicker pattern.
  • Accordion: single-open for FAQ; tooltips reveal on hover + focus with a short delay, dismiss on blur.
  • Form validation: inline below the field on blur; error state uses the semantic red #e23c3c, never color-only (pair with text).
  • Empty/feature states stay text-forward: a one-line label plus a 500-weight action link, not illustration.
  • Loading states: skeleton or the framer loading spinner for content; inline state change for buttons. No full-page overlays.
Approachdesktop-first

Desktop-first because the audience is operational and technical teams on wide displays, and the content lives in a calm bounded 1200px rail. Mobile reflows the same single-family, single-accent language into the narrower sub-rails (360–792px) without inventing an alternate architecture — the page is the page, just reflowed.

  • Observed breakpoints: sm 640 / md 768 / lg 960 / xl 1280 / 2xl 1520. Note lg is 960 (not 1024) and 2xl is 1520 — match the source, don't assume the Tailwind default ladder.
  • Container max 1200px; nested content rails at 360 / 480 / 592 / 680 / 792px for prose and form clusters.
  • Hide-on-mobile is banned — if a control exists on desktop it must reach mobile via reflow.
  • Tap target minimum 44×44 on touch; 40×40 on pointer.
  • Typography scales down proportionally: hero 80 → 48 → ~36, headings drop per tier while negative tracking eases (less negative at smaller sizes).
  • focus-visible: 2px teal (#17b267) ring with offset on every interactive element. Mandatory — never rely on the default browser outline alone.
  • All interactive elements reachable via Tab in logical reading order; never rely on hover to expose actions.
  • Color contrast: off-white #f3fbe9 on green-black #0a2414 clears AA for body text; verify the teal #17b267 against its background reaches 4.5:1 for any text use, and 3:1 minimum for large display.
  • Inline blue links (#0000ee) must remain distinguishable from body by more than color — keep the underline; never signal a link by hue alone.
  • ARIA labels on icon-only buttons; aria-expanded on collapsible regions; aria-live='polite' on toast and status updates.
  • Error state (#e23c3c) is always paired with text or an icon — never color-only signaling.
  • Motion respects prefers-reduced-motion — the single 0.4s transition reduces to opacity-only or disables.
  • Tap targets minimum 44×44 on touch; 40×40 on pointer.
Framer MotionFramer (build platform)Next/Image-equivalent

Framer Motion is the confirmed runtime (evidence: window.MotionIsMounted); the page is built on the Framer platform (framerusercontent.com asset hosts, framer-loading-spin animation). Images are framer-optimized PNGs with responsive srcset; the hero loads eagerly (above-fold) while the long feature/logo set is lazy. Icons are stroke-based, 1.5–2px weight.

  • Framer Motion `motion.div` with `whileInView` + `viewport={{ once: true }}` for scroll reveals
  • Transitions use `ease: [0.44, 0, 0.56, 1]` and `duration: 0.4` — constants only, no springs
  • useReducedMotion guard wraps every animation primitive — no exceptions
  • Responsive images with `srcset`/`sizes` always set; eager-load only the above-fold hero, lazy-load the rest
  • No canvas, no WebGL, no Lottie — static-first, animated-discreet
  • Carry the whole page on ABC Favorit at weights 400 and 500 only; reach for Geist Mono exclusively for tiny uppercase eyebrow labels.
  • Keep the teal #17b267 as the single emphasis accent and reserve the classic blue #0000ee for inline prose links.
  • Apply negative px tracking on display sizes (-1.6 / -0.96 / -0.48 / -0.18px), tightening as size grows.
  • Reach for the three-layer whisper shadow or the 4%-tint hairline before any heavier elevation.
  • Keep all motion on cubic-bezier(0.44, 0, 0.56, 1) at 0.4s — one curve, one duration, everywhere.
  • Bound content to the 1200px rail and nest prose in the narrow 360–792px sub-rails.
  • Pass every page through useReducedMotion before shipping.
  • Never introduce a second display or serif face — the single-family ABC Favorit commitment is the entire authority.
  • Never substitute 600 or 700 weights for the 400/500 ladder — emphasis is the Medium step and size, not a heavier cut.
  • Never add a second loud accent alongside the teal — color stays punctuation; the teal works because it's alone.
  • Never invent a motion duration outside 0.4s or a second easing beyond cubic-bezier(0.44, 0, 0.56, 1); no springs, no parallax, no ambient loops.
  • Never raise the elevation alpha past the captured whisper range (≤18% total) — surfaces register as edges, not floating cards.
  • Never use em for display tracking — the px-based negative scale is an optical constant, not layout-relative.
  • Never let prose run the full 1200px container width — keep it inside the narrow sub-rails.
  • Tailwind v4 @theme inline only — no runtime style concatenation, no CSS-in-JS.
  • Spacing scale: 4 / 8 / 10 / 12 / 16 / 20 / 24 / 30 / 33 / 40 / 60 / 62px.
  • Container max 1200px; nested rails 360 / 480 / 592 / 680 / 792px — do not exceed 1200.
  • Single font family + mono: ABC Favorit (400/500) + Geist Mono (labels only).
  • Weight ladder strictly 400 / 500.
  • Motion: one duration (0.4s) and one easing (cubic-bezier(0.44, 0, 0.56, 1)). No springs.
  • Radius scale: 6 / 8 / 9 / 10 / 12px.
  • Brand colors: canvas #0a2414, foreground #f3fbe9, accent teal #17b267, link blue #0000ee, error #e23c3c.
  • Container width: no page exceeds 1200px wide; prose stays inside the 360–792px sub-rails.
  • Spacing grep: no values outside the 4/8/10/12/16/20/24/30/33/40/60/62px ladder.
  • Font-family grep: only ABC Favorit (heading + body) and Geist Mono (eyebrow labels) appear — no serif, no second display face.
  • Font-weight grep: only 400 and 500 appear — no 600 or 700.
  • Color grep: teal #17b267 is the only emphasis accent; inline links use #0000ee; no second loud accent present.
  • Transition grep: every `transition-timing-function` is cubic-bezier(0.44, 0, 0.56, 1) and every duration is 0.4s — no other curve or duration.
  • Shadow audit: elevation uses the whisper three-layer stack or the 4% tint hairline; total visible opacity ≤ ~18%.
  • Tracking audit: display-size text uses px-based negative tracking (-1.6 / -0.96 / -0.48 / -0.18px), not em.
  • Radius audit: every corner draws from 6 / 8 / 9 / 10 / 12px.
  • Contrast audit: body text on the darkest background ≥ 4.5:1 (WCAG AA); inline links distinguishable beyond color.

Design tokens

Observed token system

Color, type, spacing, gradients, and stacking order captured from the live page and rendered here as living, paste-ready previews.

Inspector

Observable layers

Structure, breakpoints, motion, fonts, and images captured from the live page and kept paste-ready alongside the tokens.

Depth-first walk of the meaningful sections. 2 nodes across 2 levels, shallow to deep by color.

  • body1
    • div (×2)

Accessibility

Contrast matrix

296 combinations - 152 pass AA - 98 pass AAA. Each pair is previewed with its real foreground on background; APCA Lc sits alongside the WCAG 2.1 ratio for draft WCAG 3 awareness.

Normal text passes AAALarge text passes AAA
fg
#000000
bg
#FFFFFF
APCA Lc
+106
Use
foreground on background
Normal text passes AAALarge text passes AAA
fg
#FFFFFF
bg
#000000
APCA Lc
-108
Use
background on foreground
Normal text passes AAALarge text passes AAA
fg
#000000
bg
#FFFFFE
APCA Lc
+106
Use
foreground on background
Normal text passes AAALarge text passes AAA
fg
#FFFFFE
bg
#000000
APCA Lc
-108
Use
background on foreground
Normal text passes AAALarge text passes AAA
fg
#000000
bg
#F7FAF9
APCA Lc
+103
Use
foreground on background
Normal text passes AAALarge text passes AAA
fg
#F7FAF9
bg
#000000
APCA Lc
-104
Use
background on foreground
Normal text passes AAALarge text passes AAA
fg
#000000
bg
#F3FBE9
APCA Lc
+102
Use
foreground on background
Normal text passes AAALarge text passes AAA
fg
#F3FBE9
bg
#000000
APCA Lc
-103
Use
background on foreground
Normal text passes AAALarge text passes AAA
fg
#000000
bg
#F9F6F1
APCA Lc
+101
Use
foreground on background

Images

Image strategy

Observable image posture - total count, lazy-loading ratio, and format mix. The hero image is measured above the fold.

Total images
29
Lazy loaded
83%
Format mix
  • png23 · 79%
  • svg6 · 21%

Hero image

https://framerusercontent.com/images/HniGCslQmEkXBEZ62EGDp5rlLV0.png?scale-down-to=2048&width=4261&height=3478
Format
PNG
Dimensions
1224x999
Loading
auto
srcset
yes
srcset descriptor
https://framerusercontent.com/images/HniGCslQmEkXBEZ62EGDp5rlLV0.png?scale-down-to=512&width=4261&height=3478 512w,https://framerusercontent.com/images/HniGCslQmEkXBEZ62EGDp5rlLV0.png?scale-down-to=1024&width=4261&height=3478 1024w,https://framerusercontent.com/images/HniGCslQmEkXBEZ62EGDp5rlLV0.png?scale-down-to=2048&width=4261&height=3478 2048w,https://framerusercontent.com/images/HniGCslQmEkXBEZ62EGDp5rlLV0.png?scale-down-to=4096&width=4261&height=3478 4096w,https://framerusercontent.com/images/HniGCslQmEkXBEZ62EGDp5rlLV0.png?width=4261&height=3478 4261w
Industry
saas
Industry
developer-tools
Theme
Dark
Added
2026-06-23

FAQ

Questions people ask about Plain

3questions

Answers are pulled from the curator verdict and design brief - the same text your AI agent sees when it paste-reads this page.

Compare this with