hermes-hub/.agents/skills/frontend-design/examples/example-saas.html

1273 lines
42 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Latch — Feature flags that don't get in the way</title>
<meta name="description" content="Latch is a feature flag system for product teams who ship every day. Toggle, target, and roll back in under 50ms — without the YAML.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
/* ============================================================
LATCH — feature flags for product teams
Style: Refined Minimal, dark, Linear-style
Palette: dark surface + warm-tinted white ink + green accent
============================================================ */
:root {
--surface: #0A0A0B;
--surface-1: #131316;
--surface-2: #1C1C20;
--surface-3: #26262C;
--surface-sunken: #050507;
--ink: #F4F4F5;
--ink-muted: #A1A1AA;
--ink-subtle: #71717A;
--hairline: #1F1F23;
--hairline-strong: #2E2E33;
--accent: #6EE7B7; /* Tailwind emerald-300 — refined mint */
--accent-strong: #34D399;
--accent-soft: rgba(110, 231, 183, 0.12);
--good: #34D399;
--warn: #FBBF24;
--bad: #F87171;
--info: #60A5FA;
--font-text: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: 'JetBrains Mono', ui-monospace, monospace;
--text-xs: 0.75rem;
--text-sm: 0.8125rem;
--text-base: 0.9375rem;
--text-md: 1.0625rem;
--text-lg: 1.25rem;
--text-xl: 1.5rem;
--text-2xl: 1.875rem;
--text-3xl: 2.25rem;
--text-4xl: 3rem;
--text-5xl: 3.75rem;
--lead-tight: 1.05;
--lead-snug: 1.2;
--lead-normal: 1.5;
--lead-loose: 1.65;
--track-tightest: -0.035em;
--track-tight: -0.02em;
--track-wide: 0.04em;
--track-widest: 0.14em;
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
--sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;
--sp-9: 96px; --sp-10: 128px;
--r-sm: 4px;
--r-md: 6px;
--r-lg: 8px;
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
margin: 0;
font-family: var(--font-text);
font-size: var(--text-base);
line-height: var(--lead-normal);
color: var(--ink);
background: var(--surface);
font-feature-settings: 'kern' 1, 'cv11' 1, 'ss01' 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
font-variant-numeric: tabular-nums;
}
img, svg { display: block; max-width: 100%; }
a {
color: inherit;
text-decoration: none;
border-bottom: 1px solid var(--hairline-strong);
padding-bottom: 1px;
transition: border-color 140ms ease, color 140ms ease;
}
a:hover { border-color: var(--accent); color: var(--accent); }
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
button, input { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
input { background: transparent; border: 0; }
::selection { background: var(--accent); color: var(--surface); }
.mono { font-family: var(--font-mono); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
/* ----- Nav ------------------------------------------------------- */
.nav {
position: sticky;
top: 0;
z-index: 10;
background: color-mix(in oklab, var(--surface) 88%, transparent);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border-bottom: 1px solid var(--hairline);
}
.nav__inner {
max-width: 1200px;
margin: 0 auto;
padding: 0 clamp(20px, 4vw, 48px);
height: 60px;
display: flex;
align-items: center;
justify-content: space-between;
}
.nav__brand {
display: inline-flex;
align-items: center;
gap: var(--sp-2);
font-weight: 600;
font-size: var(--text-md);
letter-spacing: var(--track-tight);
color: var(--ink);
border-bottom: 0;
}
.nav__brand-mark { color: var(--accent); }
.nav__links {
display: flex;
align-items: center;
gap: var(--sp-6);
font-size: var(--text-sm);
}
.nav__links a {
color: var(--ink-muted);
border-bottom: 0;
}
.nav__links a:hover { color: var(--ink); }
.nav__cta {
padding: 7px 13px;
border: 1px solid var(--hairline-strong);
border-radius: var(--r-sm);
color: var(--ink) !important;
transition: background 120ms ease, border-color 120ms ease;
}
.nav__cta:hover { background: var(--surface-1); border-color: var(--accent); }
@media (max-width: 720px) {
.nav__links a:not(.nav__cta) { display: none; }
}
/* ----- Hero ------------------------------------------------------ */
.hero {
position: relative;
padding: clamp(60px, 10vw, 120px) clamp(20px, 4vw, 48px);
max-width: 1200px;
margin: 0 auto;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(
ellipse 70% 50% at 50% 0%,
var(--accent-soft) 0%,
transparent 60%
);
pointer-events: none;
}
.hero__inner {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
gap: clamp(32px, 6vw, 64px);
align-items: center;
}
.hero__kicker {
display: inline-flex;
align-items: center;
gap: var(--sp-2);
font-family: var(--font-mono);
font-size: var(--text-xs);
letter-spacing: var(--track-widest);
text-transform: uppercase;
color: var(--ink-muted);
margin-bottom: var(--sp-6);
}
.hero__kicker-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--accent);
}
.hero__title {
font-size: clamp(2.5rem, 6vw, 5rem);
font-weight: 600;
letter-spacing: var(--track-tightest);
line-height: 1.02;
margin: 0 0 var(--sp-7) 0;
}
.hero__lede {
font-size: var(--text-md);
line-height: 1.55;
color: var(--ink-muted);
max-width: 44ch;
margin: 0 0 var(--sp-7) 0;
}
.hero__actions {
display: flex;
gap: var(--sp-3);
flex-wrap: wrap;
margin-bottom: var(--sp-4);
}
.hero__fineprint {
font-family: var(--font-mono);
font-size: 11px;
letter-spacing: var(--track-wide);
color: var(--ink-subtle);
margin: 0;
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
height: 40px;
padding: 0 16px;
font-size: var(--text-sm);
font-weight: 500;
border-radius: var(--r-md);
border: 1px solid transparent;
text-decoration: none;
cursor: pointer;
transition: background-color 140ms ease, border-color 140ms ease, color 140ms ease, transform 80ms ease;
white-space: nowrap;
border-bottom-width: 1px;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn--primary {
background: var(--accent);
color: var(--surface);
border-color: var(--accent);
font-weight: 600;
}
.btn--primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn--ghost {
background: transparent;
color: var(--ink);
border-color: var(--hairline-strong);
}
.btn--ghost:hover { border-color: var(--ink-muted); background: var(--surface-1); }
@media (max-width: 560px) {
.btn { width: 100%; }
}
/* ----- Hero panel: feature flag list ------------------------- */
.panel {
background: var(--surface-1);
border: 1px solid var(--hairline-strong);
border-radius: var(--r-lg);
overflow: hidden;
box-shadow: 0 24px 48px rgba(0,0,0,0.4), 0 4px 16px rgba(0,0,0,0.3);
}
.panel__chrome {
display: flex;
align-items: center;
gap: var(--sp-2);
padding: var(--sp-3) var(--sp-4);
background: var(--surface-2);
border-bottom: 1px solid var(--hairline);
}
.panel__dot { width: 10px; height: 10px; border-radius: 50%; background: var(--hairline-strong); }
.panel__dot:nth-child(1) { background: #FF5F57; }
.panel__dot:nth-child(2) { background: #FEBC2E; }
.panel__dot:nth-child(3) { background: #28C840; }
.panel__url {
margin-left: var(--sp-4);
font-family: var(--font-mono);
font-size: 11px;
color: var(--ink-subtle);
}
.panel__body { padding: 0; }
.panel__head {
padding: var(--sp-4);
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--hairline);
}
.panel__title {
font-size: var(--text-md);
font-weight: 600;
margin: 0;
}
.panel__seg {
display: inline-flex;
background: var(--surface-2);
border: 1px solid var(--hairline);
border-radius: var(--r-sm);
padding: 2px;
}
.panel__seg-btn {
padding: 4px 10px;
font-family: var(--font-mono);
font-size: 11px;
color: var(--ink-muted);
border-radius: 3px;
letter-spacing: var(--track-wide);
}
.panel__seg-btn--active {
background: var(--surface);
color: var(--ink);
}
/* Flag rows */
.flag-list { list-style: none; margin: 0; padding: 0; }
.flag {
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
gap: var(--sp-3);
align-items: center;
padding: var(--sp-3) var(--sp-4);
border-bottom: 1px solid var(--hairline);
font-size: var(--text-sm);
transition: background 100ms ease;
}
.flag:hover { background: var(--surface-2); }
.flag:last-child { border-bottom: 0; }
.flag__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.flag__key {
font-family: var(--font-mono);
font-size: var(--text-sm);
color: var(--ink);
font-weight: 500;
}
.flag__desc {
font-size: 12px;
color: var(--ink-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flag__env {
font-family: var(--font-mono);
font-size: 11px;
padding: 2px 8px;
border-radius: 3px;
letter-spacing: var(--track-wide);
}
.flag__env--prod { background: rgba(248, 113, 113, 0.12); color: var(--bad); }
.flag__env--stg { background: rgba(251, 191, 36, 0.12); color: var(--warn); }
.flag__env--dev { background: rgba(96, 165, 250, 0.12); color: var(--info); }
/* Toggle */
.toggle {
width: 32px;
height: 18px;
background: var(--surface-3);
border-radius: 9999px;
position: relative;
transition: background 140ms ease;
flex-shrink: 0;
}
.toggle__knob {
position: absolute;
top: 2px;
left: 2px;
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--ink-muted);
transition: transform 140ms ease, background 140ms ease;
}
.toggle--on { background: var(--accent); }
.toggle--on .toggle__knob { transform: translateX(14px); background: var(--surface); }
/* ----- Trusted-by (compact) -------------------------------- */
.trusted {
max-width: 1200px;
margin: 0 auto;
padding: var(--sp-7) clamp(20px, 4vw, 48px);
display: flex;
align-items: center;
gap: var(--sp-7);
flex-wrap: wrap;
border-top: 1px solid var(--hairline);
border-bottom: 1px solid var(--hairline);
background: var(--surface-1);
}
.trusted__label {
font-family: var(--font-mono);
font-size: var(--text-xs);
letter-spacing: var(--track-widest);
text-transform: uppercase;
color: var(--ink-subtle);
margin: 0;
}
.trusted__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
gap: var(--sp-7);
flex-wrap: wrap;
}
.trusted__item {
display: inline-flex;
align-items: baseline;
gap: var(--sp-2);
font-size: var(--text-md);
font-weight: 500;
letter-spacing: var(--track-tight);
color: var(--ink-muted);
}
.trusted__item strong { color: var(--ink); font-weight: 500; }
/* ----- Features section -------------------------------------- */
.features {
max-width: 1200px;
margin: 0 auto;
padding: clamp(80px, 12vw, 160px) clamp(20px, 4vw, 48px);
}
.section-head { margin-bottom: var(--sp-8); }
.section-head__kicker {
font-family: var(--font-mono);
font-size: var(--text-xs);
letter-spacing: var(--track-widest);
text-transform: uppercase;
color: var(--ink-muted);
margin: 0 0 var(--sp-5) 0;
}
.section-head__title {
font-size: clamp(1.875rem, 4vw, 3rem);
font-weight: 600;
letter-spacing: var(--track-tight);
line-height: 1.1;
margin: 0;
max-width: 22ch;
}
/* Feature 1 — code block */
.feature {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
gap: clamp(32px, 6vw, 64px);
align-items: center;
padding-block: clamp(48px, 7vw, 80px);
border-top: 1px solid var(--hairline);
}
.feature:first-of-type { border-top: 0; padding-top: 0; }
.feature__body .kicker {
font-family: var(--font-mono);
font-size: var(--text-xs);
letter-spacing: var(--track-widest);
text-transform: uppercase;
color: var(--ink-muted);
margin: 0 0 var(--sp-5) 0;
}
.feature__body h3 {
font-size: clamp(1.375rem, 2.4vw, 2rem);
font-weight: 600;
letter-spacing: var(--track-tight);
line-height: 1.2;
margin: 0 0 var(--sp-5) 0;
}
.feature__body p {
color: var(--ink-muted);
font-size: var(--text-md);
line-height: 1.55;
max-width: 44ch;
margin: 0 0 var(--sp-5) 0;
}
.feature__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--sp-2);
font-size: var(--text-sm);
color: var(--ink-muted);
}
.feature__list li {
padding-left: var(--sp-5);
position: relative;
}
.feature__list li::before {
content: '';
position: absolute;
left: 0;
top: 0.6em;
width: 12px;
height: 1px;
background: var(--accent);
}
/* Code block */
.codeblock {
background: var(--surface-sunken);
border: 1px solid var(--hairline-strong);
border-radius: var(--r-lg);
overflow: hidden;
}
.codeblock__head {
display: flex;
justify-content: space-between;
padding: var(--sp-3) var(--sp-4);
border-bottom: 1px solid var(--hairline);
background: var(--surface-1);
font-family: var(--font-mono);
font-size: var(--text-xs);
color: var(--ink-muted);
letter-spacing: var(--track-wide);
}
.codeblock__file { color: var(--ink); }
.codeblock__body {
margin: 0;
padding: var(--sp-5);
overflow-x: auto;
font-family: var(--font-mono);
font-size: 13px;
line-height: 1.65;
color: var(--ink);
}
.tok-cmt { color: var(--ink-subtle); font-style: italic; }
.tok-key { color: #C792EA; }
.tok-str { color: #C3E88D; }
.tok-fn { color: #82AAFF; }
.tok-var { color: #F78C6C; }
.tok-num { color: #F78C6C; }
/* Feature 2 — flags visualization */
.viz-flags {
background: var(--surface-1);
border: 1px solid var(--hairline-strong);
border-radius: var(--r-lg);
padding: var(--sp-5);
}
.viz-flags__head {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--sp-4);
}
.viz-flags__head h4 {
font-size: var(--text-sm);
font-weight: 600;
margin: 0;
}
.viz-flags__count {
font-family: var(--font-mono);
font-size: 11px;
letter-spacing: var(--track-wide);
color: var(--ink-muted);
}
.viz-flags__row {
display: grid;
grid-template-columns: 1fr 60px 60px 60px;
gap: var(--sp-3);
padding: var(--sp-3) 0;
border-top: 1px solid var(--hairline);
align-items: center;
font-size: var(--text-sm);
}
.viz-flags__row:first-of-type { border-top: 0; }
.viz-flags__name {
font-family: var(--font-mono);
font-size: var(--text-xs);
color: var(--ink);
}
.viz-flags__pct {
font-family: var(--font-mono);
font-size: var(--text-xs);
color: var(--ink-muted);
text-align: right;
}
.viz-flags__bar {
height: 6px;
background: var(--surface-3);
border-radius: 3px;
overflow: hidden;
position: relative;
}
.viz-flags__bar-fill {
position: absolute;
inset: 0;
width: var(--pct);
background: var(--accent);
border-radius: 3px;
}
@media (max-width: 880px) {
.hero__inner,
.feature {
grid-template-columns: 1fr;
gap: var(--sp-7);
}
.viz-flags__row { grid-template-columns: 1fr 50px 50px 50px; }
}
/* ----- Pricing ----------------------------------------------- */
.pricing {
max-width: 1200px;
margin: 0 auto;
padding: clamp(80px, 12vw, 160px) clamp(20px, 4vw, 48px);
border-top: 1px solid var(--hairline);
}
.pricing__grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--sp-5);
max-width: 880px;
}
@media (max-width: 720px) {
.pricing__grid { grid-template-columns: 1fr; }
}
.plan {
background: var(--surface-1);
border: 1px solid var(--hairline-strong);
border-radius: var(--r-lg);
padding: var(--sp-7);
display: flex;
flex-direction: column;
gap: var(--sp-5);
}
.plan--featured {
border-color: var(--accent);
background: linear-gradient(180deg, var(--accent-soft) 0%, var(--surface-1) 40%);
}
.plan__head { padding-bottom: var(--sp-5); border-bottom: 1px solid var(--hairline); }
.plan__name {
font-family: var(--font-mono);
font-size: var(--text-xs);
letter-spacing: var(--track-widest);
text-transform: uppercase;
color: var(--ink-muted);
margin: 0 0 var(--sp-4) 0;
}
.plan--featured .plan__name { color: var(--accent); }
.plan__price {
font-size: var(--text-4xl);
font-weight: 600;
letter-spacing: var(--track-tight);
margin: 0;
line-height: 1;
}
.plan__period {
font-size: var(--text-md);
color: var(--ink-muted);
font-weight: 500;
}
.plan__sub {
margin: var(--sp-3) 0 0 0;
font-size: var(--text-sm);
color: var(--ink-muted);
}
.plan__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--sp-3);
font-size: var(--text-sm);
flex: 1;
}
.plan__list li {
display: flex;
align-items: flex-start;
gap: var(--sp-3);
}
.plan__list li::before {
content: '✓';
color: var(--accent);
font-weight: 600;
flex-shrink: 0;
font-family: var(--font-mono);
}
/* ----- CTA --------------------------------------------------- */
.cta {
max-width: 1200px;
margin: 0 auto;
padding: clamp(80px, 12vw, 160px) clamp(20px, 4vw, 48px);
border-top: 1px solid var(--hairline);
text-align: center;
}
.cta__title {
font-size: clamp(2rem, 4.5vw, 3.5rem);
font-weight: 600;
letter-spacing: var(--track-tight);
line-height: 1.1;
margin: 0;
}
.cta__sub {
color: var(--ink-muted);
font-size: var(--text-md);
max-width: 50ch;
margin: var(--sp-5) auto 0;
}
.cta__form {
display: flex;
gap: var(--sp-2);
max-width: 460px;
margin: var(--sp-7) auto 0;
}
.cta__input {
flex: 1;
height: 44px;
padding: 0 var(--sp-4);
background: var(--surface-1);
border: 1px solid var(--hairline-strong);
border-radius: var(--r-md);
color: var(--ink);
font-size: var(--text-sm);
transition: border-color 140ms ease;
}
.cta__input::placeholder { color: var(--ink-subtle); }
.cta__input:focus { border-color: var(--accent); outline: none; }
.cta__input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 560px) {
.cta__form { flex-direction: column; }
}
/* ----- Footer ----------------------------------------------- */
.footer {
padding: var(--sp-8) clamp(20px, 4vw, 48px);
border-top: 1px solid var(--hairline);
background: var(--surface-1);
}
.footer__inner {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
gap: var(--sp-8);
}
.footer__brand {
display: inline-flex;
align-items: center;
gap: var(--sp-2);
font-size: var(--text-md);
font-weight: 600;
letter-spacing: var(--track-tight);
color: var(--ink);
}
.footer__brand .nav__brand-mark { color: var(--accent); }
.footer__nav {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--sp-7);
}
.footer__nav .kicker {
font-family: var(--font-mono);
font-size: var(--text-xs);
letter-spacing: var(--track-widest);
text-transform: uppercase;
color: var(--ink-muted);
margin: 0 0 var(--sp-3) 0;
}
.footer__nav a {
display: block;
color: var(--ink-muted);
font-size: var(--text-sm);
padding: 4px 0;
border-bottom: 0;
}
.footer__nav a:hover { color: var(--ink); }
.footer__bot {
max-width: 1200px;
margin: var(--sp-7) auto 0;
padding-top: var(--sp-5);
border-top: 1px solid var(--hairline);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: var(--sp-3);
}
.footer__meta { margin: 0; font-size: var(--text-xs); color: var(--ink-muted); }
.footer__build {
margin: 0;
font-family: var(--font-mono);
font-size: 11px;
color: var(--ink-subtle);
letter-spacing: var(--track-wide);
}
@media (max-width: 720px) {
.footer__inner, .footer__nav { grid-template-columns: 1fr; gap: var(--sp-7); }
.footer__nav { grid-template-columns: repeat(2, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
</style>
</head>
<body>
<!-- ====== NAV ============================================== -->
<header class="nav" role="banner">
<div class="nav__inner">
<a href="#" class="nav__brand" aria-label="Latch — home">
<svg class="nav__brand-mark" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true">
<path d="M4 5 H16 V8 H4 Z M4 12 H12 V15 H4 Z" fill="currentColor"/>
</svg>
<span>Latch</span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#product">Product</a>
<a href="#pricing">Pricing</a>
<a href="#">Docs</a>
<a href="#">Sign in</a>
<a href="#cta" class="nav__cta">Start free →</a>
</nav>
</div>
</header>
<main id="main">
<!-- ====== HERO ============================================== -->
<section class="hero" aria-labelledby="hero-title">
<div class="hero__inner">
<div>
<p class="hero__kicker">
<span class="hero__kicker-dot" aria-hidden="true"></span>
v3.2 — Now with local evaluation, 0ms overhead
</p>
<h1 id="hero-title" class="hero__title">
Feature flags<br>
that don't<br>
get in the way.
</h1>
<p class="hero__lede">
Toggle, target, and roll back in under 50ms — without
the YAML, without the SDK lock-in, without the
dashboard that takes ten clicks to flip one switch.
</p>
<div class="hero__actions">
<a href="#cta" class="btn btn--primary">Start free — no card</a>
<a href="#install" class="btn btn--ghost">See the install</a>
</div>
<p class="hero__fineprint">Free up to 100k evaluations / month · No credit card · 5-minute setup</p>
</div>
<!-- Flag panel mockup -->
<figure aria-label="Latch dashboard — flags list">
<div class="panel">
<div class="panel__chrome">
<span class="panel__dot"></span>
<span class="panel__dot"></span>
<span class="panel__dot"></span>
<span class="panel__url">latch.run / flags / acme-prod</span>
</div>
<div class="panel__body">
<div class="panel__head">
<h3 class="panel__title">Flags</h3>
<div class="panel__seg" role="tablist" aria-label="Environment">
<button class="panel__seg-btn" role="tab">Dev</button>
<button class="panel__seg-btn" role="tab">Stg</button>
<button class="panel__seg-btn panel__seg-btn--active" role="tab" aria-selected="true">Prod</button>
</div>
</div>
<ul class="flag-list" role="list">
<li class="flag">
<div class="flag__main">
<span class="flag__key">checkout-v3-redesign</span>
<span class="flag__desc">New checkout flow with Apple Pay</span>
</div>
<span class="flag__env flag__env--prod">prod</span>
<span class="toggle toggle--on" role="img" aria-label="Enabled"><span class="toggle__knob"></span></span>
</li>
<li class="flag">
<div class="flag__main">
<span class="flag__key">ai-summarize-beta</span>
<span class="flag__desc">GPT-4 summary on doc pages</span>
</div>
<span class="flag__env flag__env--stg">stg</span>
<span class="toggle toggle--on" role="img" aria-label="Enabled"><span class="toggle__knob"></span></span>
</li>
<li class="flag">
<div class="flag__main">
<span class="flag__key">dark-mode-default</span>
<span class="flag__desc">Auto-dark for system pref users</span>
</div>
<span class="flag__env flag__env--prod">prod</span>
<span class="toggle toggle--on" role="img" aria-label="Enabled"><span class="toggle__knob"></span></span>
</li>
<li class="flag">
<div class="flag__main">
<span class="flag__key">referral-rewards-v2</span>
<span class="flag__desc">New tiered referral program</span>
</div>
<span class="flag__env flag__env--prod">prod</span>
<span class="toggle" role="img" aria-label="Disabled"><span class="toggle__knob"></span></span>
</li>
<li class="flag">
<div class="flag__main">
<span class="flag__key">edge-cache-rewrite</span>
<span class="flag__desc">New CDN invalidation logic</span>
</div>
<span class="flag__env flag__env--dev">dev</span>
<span class="toggle" role="img" aria-label="Disabled"><span class="toggle__knob"></span></span>
</li>
<li class="flag">
<div class="flag__main">
<span class="flag__key">homepage-experiment-q1</span>
<span class="flag__desc">50/50 split, 14 day window</span>
</div>
<span class="flag__env flag__env--prod">prod</span>
<span class="toggle toggle--on" role="img" aria-label="Enabled"><span class="toggle__knob"></span></span>
</li>
</ul>
</div>
</div>
</figure>
</div>
</section>
<!-- ====== TRUSTED-BY ======================================== -->
<section class="trusted" aria-label="Customers">
<p class="trusted__label">In production at</p>
<ul class="trusted__list" role="list">
<li class="trusted__item"><strong>Plover</strong> · payments</li>
<li class="trusted__item"><strong>Northwind</strong> · B2B SaaS</li>
<li class="trusted__item"><strong>Cobalt</strong> · dev tools</li>
<li class="trusted__item"><strong>Quill</strong> · editorial CMS</li>
</ul>
</section>
<!-- ====== FEATURES ========================================== -->
<section id="product" class="features" aria-labelledby="features-heading">
<header class="section-head">
<p class="section-head__kicker">§ 01 — The product</p>
<h2 id="features-heading" class="section-head__title">
Three things every flag<br>
system should do. Latch<br>
does all three well.
</h2>
</header>
<!-- Feature 1: install -->
<article id="install" class="feature">
<div class="feature__body">
<p class="kicker">01 · Install</p>
<h3>Four lines of code. Live in 4 minutes.</h3>
<p>
One env var, one import, one provider. Latch works with
Next.js, Remix, Rails, Django, Go, anything that can
read an environment variable. Local evaluation means
<strong>zero network round-trips</strong> in production.
</p>
<ul class="feature__list" role="list">
<li>~12 KB gzipped SDK, no dependencies</li>
<li>Works in edge runtimes (Vercel, Cloudflare)</li>
<li>Open-source SDKs in 7 languages</li>
<li>SOC 2 Type II, EU and US data residency</li>
</ul>
</div>
<div>
<div class="codeblock">
<div class="codeblock__head">
<span class="codeblock__file">app/layout.tsx</span>
<span>TypeScript</span>
</div>
<pre class="codeblock__body"><code><span class="tok-cmt">// 1. Install</span>
<span class="tok-key">npm i</span> <span class="tok-str">@latch/sdk</span>
<span class="tok-cmt">// 2. Set your key</span>
<span class="tok-var">LATCH_KEY</span>=<span class="tok-str">lk_live_••••••••••••</span>
<span class="tok-cmt">// 3. Use it</span>
<span class="tok-key">import</span> { latch } <span class="tok-key">from</span> <span class="tok-str">'@latch/sdk'</span>
<span class="tok-key">if</span> (latch.<span class="tok-fn">isOn</span>(<span class="tok-str">'checkout-v3-redesign'</span>)) {
<span class="tok-key">return</span> &lt;<span class="tok-fn">NewCheckout</span> /&gt;
}
<span class="tok-key">return</span> &lt;<span class="tok-fn">LegacyCheckout</span> /&gt;</code></pre>
</div>
</div>
</article>
<!-- Feature 2: targeting -->
<article class="feature">
<div>
<div class="viz-flags">
<div class="viz-flags__head">
<h4>Rollout · homepage-experiment-q1</h4>
<span class="viz-flags__count">3 segments · 14 days</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">Returning US</span>
<span class="viz-flags__pct mono">100%</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 100%"></span></span>
<span class="viz-flags__pct mono">142k</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">New EU</span>
<span class="viz-flags__pct mono">50%</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 50%"></span></span>
<span class="viz-flags__pct mono">28k</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">Mobile / iOS 17</span>
<span class="viz-flags__pct mono">25%</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 25%"></span></span>
<span class="viz-flags__pct mono">9.4k</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">Beta program</span>
<span class="viz-flags__pct mono">100%</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 100%"></span></span>
<span class="viz-flags__pct mono">2.1k</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">Everyone else</span>
<span class="viz-flags__pct mono">0%</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 0%"></span></span>
<span class="viz-flags__pct mono"></span>
</div>
</div>
</div>
<div class="feature__body">
<p class="kicker">02 · Targeting</p>
<h3>Target by anything. Roll out in real time.</h3>
<p>
Segment by user attributes, geography, plan, device,
cohort, or anything you send. Build segments in the UI,
or define them in code — Latch syncs both directions.
Roll back in one click. Pause a flag globally in &lt;200ms.
</p>
<ul class="feature__list" role="list">
<li>Targeting by 20+ attributes out of the box</li>
<li>Custom attributes via SDK</li>
<li>A/B testing with built-in statistical significance</li>
<li>Audit log of every change, every change-maker</li>
</ul>
</div>
</article>
<!-- Feature 3: speed -->
<article class="feature">
<div class="feature__body">
<p class="kicker">03 · Speed</p>
<h3>Sub-50ms evaluations. Even at the edge.</h3>
<p>
Latch evaluates flags locally from a 2KB signed payload
that ships with your build. There's no round-trip to
a control plane, no network jitter, no cold-start penalty.
Your slowest flag check is faster than your fastest
database query.
</p>
<ul class="feature__list" role="list">
<li>p50: 0.4ms · p95: 2.1ms · p99: 8ms (cold)</li>
<li>Payload cached in CDN, refreshed every 30s</li>
<li>Works offline (last-known-good payload)</li>
<li>No runtime dependency on Latch being up</li>
</ul>
</div>
<div>
<div class="viz-flags">
<div class="viz-flags__head">
<h4>Evaluation latency · last 24h</h4>
<span class="viz-flags__count">p95 = 2.1ms</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">p50</span>
<span class="viz-flags__pct mono">0.4ms</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 4%"></span></span>
<span class="viz-flags__pct mono">~</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">p75</span>
<span class="viz-flags__pct mono">1.0ms</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 10%"></span></span>
<span class="viz-flags__pct mono">~</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">p95</span>
<span class="viz-flags__pct mono">2.1ms</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 21%"></span></span>
<span class="viz-flags__pct mono">~</span>
</div>
<div class="viz-flags__row">
<span class="viz-flags__name">p99</span>
<span class="viz-flags__pct mono">8.0ms</span>
<span class="viz-flags__bar"><span class="viz-flags__bar-fill" style="--pct: 80%"></span></span>
<span class="viz-flags__pct mono">~</span>
</div>
</div>
</div>
</article>
</section>
<!-- ====== PRICING =========================================== -->
<section id="pricing" class="pricing" aria-labelledby="pricing-heading">
<header class="section-head">
<p class="section-head__kicker">§ 02 — Pricing</p>
<h2 id="pricing-heading" class="section-head__title">Two plans. Both honest.</h2>
</header>
<div class="pricing__grid">
<article class="plan">
<header class="plan__head">
<p class="plan__name">Hobby</p>
<p class="plan__price">$0<span class="plan__period"> / month</span></p>
<p class="plan__sub">For side projects and prototypes. Free forever.</p>
</header>
<ul class="plan__list" role="list">
<li>100,000 evaluations / month</li>
<li>Unlimited flags</li>
<li>3 environments</li>
<li>3 team members</li>
<li>Community support</li>
</ul>
<a href="#cta" class="btn btn--ghost">Start free</a>
</article>
<article class="plan plan--featured">
<header class="plan__head">
<p class="plan__name">Production</p>
<p class="plan__price">$320<span class="plan__period"> / month</span></p>
<p class="plan__sub">For apps with real traffic. Includes everything in Hobby.</p>
</header>
<ul class="plan__list" role="list">
<li>5M evaluations / month, then $0.06 / 100k</li>
<li>Unlimited environments, unlimited members</li>
<li>A/B testing + statistical significance</li>
<li>Audit log, RBAC, SAML SSO</li>
<li>EU + US data residency</li>
<li>SOC 2 Type II report</li>
<li>4-hour response SLA, shared Slack channel</li>
</ul>
<a href="#cta" class="btn btn--primary">Start 14-day trial</a>
</article>
</div>
</section>
<!-- ====== CTA =============================================== -->
<section id="cta" class="cta" aria-labelledby="cta-title">
<h2 id="cta-title" class="cta__title">Ship a flag in the next 4 minutes.</h2>
<p class="cta__sub">Free up to 100k evaluations / month · No credit card · Cancel any time</p>
<form class="cta__form" action="#" method="post" novalidate>
<label for="email" class="sr-only">Work email</label>
<input id="email" type="email" required class="cta__input"
placeholder="you@company.com" autocomplete="email">
<button type="submit" class="btn btn--primary">Get started →</button>
</form>
</section>
</main>
<!-- ====== FOOTER ============================================ -->
<footer class="footer" role="contentinfo">
<div class="footer__inner">
<div>
<a href="#" class="footer__brand">
<svg class="nav__brand-mark" width="18" height="18" viewBox="0 0 20 20" aria-hidden="true">
<path d="M4 5 H16 V8 H4 Z M4 12 H12 V15 H4 Z" fill="currentColor"/>
</svg>
<span>Latch</span>
</a>
</div>
<nav class="footer__nav" aria-label="Footer">
<div>
<p class="kicker">Product</p>
<a href="#">Flags</a>
<a href="#">Targeting</a>
<a href="#">Experiments</a>
<a href="#">Pricing</a>
</div>
<div>
<p class="kicker">Resources</p>
<a href="#">Docs</a>
<a href="#">API</a>
<a href="#">Status</a>
<a href="#">Security</a>
</div>
<div>
<p class="kicker">Company</p>
<a href="#">About</a>
<a href="#">Customers</a>
<a href="#">Blog</a>
<a href="#">Careers</a>
</div>
</nav>
</div>
<div class="footer__bot">
<p class="footer__meta">© 20242026 Latch Labs, Inc. · Made in Berlin and Lisbon</p>
<p class="footer__build">v3.2.7 · build 8f4a12 · uptime 99.99% · region eu-west-1</p>
</div>
</footer>
<script>
// Segmented control — keyboard + click
document.querySelectorAll('.panel__seg').forEach(function (group) {
const btns = group.querySelectorAll('.panel__seg-btn');
btns.forEach(function (btn) {
btn.addEventListener('click', function () {
btns.forEach(function (b) {
b.classList.remove('panel__seg-btn--active');
b.setAttribute('aria-selected', 'false');
});
btn.classList.add('panel__seg-btn--active');
btn.setAttribute('aria-selected', 'true');
});
});
});
// Toggle interaction (demo only)
document.querySelectorAll('.toggle').forEach(function (t) {
t.addEventListener('click', function () {
t.classList.toggle('toggle--on');
});
t.addEventListener('keydown', function (e) {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
t.classList.toggle('toggle--on');
}
});
t.setAttribute('tabindex', '0');
t.setAttribute('role', 'switch');
});
</script>
</body>
</html>