feat(website): responsive / mobile layouts

Make the marketing site mobile-friendly across every page and section.
Desktop appearance is unchanged; all breakpoint logic targets <=768px.

- Fluid section padding via clamp(); equal grids use auto-fit/minmax,
  asymmetric grids stack to one column via scoped-CSS media queries
- Nav: real hamburger menu on mobile (links, lang toggle, login, CTA)
- ProductMockup: scales the whole dashboard to fit (zoom) instead of
  reflowing its internals into a tall stack
- Lower oversized heading clamp() minimums so titles no longer overflow
  at ~390px (hero, page headers, final CTA, brand cover/chapter)
- HowItWorks: row-gap when steps stack so node markers clear the text
- Compare + partners tables: stacked rows now label each value with its
  column (Dezky vs hyperscaler / CSP) instead of an ambiguous header
- Footer columns, tiers, calculator and tables stack cleanly on mobile
This commit is contained in:
Ronni Baslund
2026-06-06 15:55:35 +02:00
parent bc0697c3e8
commit d668b1b6a6
28 changed files with 721 additions and 142 deletions
+108 -42
View File
@@ -24,10 +24,10 @@ function frame(bg: string, height?: number, fg?: string) {
}
const eyebrow = { fontFamily: mono, fontSize: '11px', letterSpacing: '0.18em', textTransform: 'uppercase' as const, fontWeight: 500, opacity: 0.7 }
const h1 = { fontFamily: tight, fontWeight: 600, fontSize: 'clamp(48px, 6vw, 72px)', letterSpacing: '-0.035em', lineHeight: 0.95, margin: '24px 0 0', textWrap: 'balance' as const }
const h1 = { fontFamily: tight, fontWeight: 600, fontSize: 'clamp(32px, 6vw, 72px)', letterSpacing: '-0.035em', lineHeight: 0.95, margin: '24px 0 0', textWrap: 'balance' as const }
const h2 = { fontFamily: tight, fontWeight: 600, fontSize: 'clamp(36px, 4.5vw, 52px)', letterSpacing: '-0.03em', lineHeight: 1, margin: '20px 0 56px', textWrap: 'balance' as const }
const caption = { fontFamily: mono, fontSize: '10px', letterSpacing: '0.12em', textTransform: 'uppercase' as const, color: 'rgba(0,0,0,0.5)', marginTop: '10px' }
const page = { padding: '96px 80px', borderBottom: `1px solid ${C.fog}` }
const page = { padding: 'clamp(56px, 8vw, 96px) clamp(20px, 5vw, 80px)', borderBottom: `1px solid ${C.fog}` }
const bigSwatches = [
{ name: 'Carbon', hex: C.carbon, rgb: '10 10 10', role: 'Foreground · containers · type', dark: true },
@@ -99,11 +99,11 @@ const doDont: DoDont[] = [
<template>
<div :style="{ background: C.paper, color: C.carbon }">
<!-- 00 · COVER -->
<section :style="{ background: C.carbon, color: C.bone, padding: '80px 80px', minHeight: '86vh', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', position: 'relative', overflow: 'hidden' }">
<section :style="{ background: C.carbon, color: C.bone, padding: 'clamp(56px, 8vw, 80px) clamp(20px, 5vw, 80px)', minHeight: '86vh', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', position: 'relative', overflow: 'hidden' }">
<div :style="{ position: 'absolute', right: '-160px', bottom: '-160px', opacity: 0.06 }">
<BrandNodeMark :size="720" :fg="C.carbon" :accent="C.signal" />
</div>
<div :style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', position: 'relative' }">
<div :style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', position: 'relative', flexWrap: 'wrap', gap: '16px' }">
<div :style="{ display: 'flex', alignItems: 'center', gap: '14px' }">
<div :style="{ width: '56px', height: '56px', background: C.bone, borderRadius: '14px', display: 'flex', alignItems: 'center', justifyContent: 'center' }">
<BrandNodeMark :size="44" :fg="C.carbon" :accent="C.signal" />
@@ -117,12 +117,12 @@ const doDont: DoDont[] = [
</div>
<div :style="{ position: 'relative' }">
<div :style="eyebrow">The dezky brand</div>
<h1 :style="{ fontFamily: tight, fontWeight: 600, fontSize: 'clamp(64px, 11vw, 144px)', letterSpacing: '-0.045em', lineHeight: 0.9, margin: '32px 0 0', maxWidth: '90%' }">
<h1 :style="{ fontFamily: tight, fontWeight: 600, fontSize: 'clamp(34px, 11vw, 144px)', letterSpacing: '-0.045em', lineHeight: 0.9, margin: '32px 0 0', maxWidth: '90%' }">
Quiet software,<br>
<span :style="{ color: C.signal }">sovereign data.</span>
</h1>
</div>
<div :style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', color: 'rgba(255,255,255,0.55)', fontFamily: mono, fontSize: '11px', position: 'relative' }">
<div :style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', color: 'rgba(255,255,255,0.55)', fontFamily: mono, fontSize: '11px', position: 'relative', flexWrap: 'wrap', gap: '8px' }">
<div>dezky · brand system</div>
<div>00 / 06</div>
</div>
@@ -133,14 +133,14 @@ const doDont: DoDont[] = [
<div :style="eyebrow">01 · Logo</div>
<h1 :style="h1">The mark</h1>
<p :style="pStyle(560, true)">A lowercase <i>d</i> built as a unified letterform full bowl, rounded ascender, contained in a squircle. The node-dot in the upper-right is the one moving piece of the brand: a signal, a presence.</p>
<div :style="{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: '24px', marginTop: '64px' }">
<div class="logo-main-grid" :style="{ display: 'grid', gap: '24px', marginTop: '64px' }">
<div :style="frame(C.carbon, 520)"><BrandNodeMark :size="360" :fg="C.carbon" :accent="C.signal" /></div>
<div :style="{ display: 'grid', gridTemplateRows: '1fr 1fr', gap: '24px', height: '520px' }">
<div :style="frame(C.signal)"><BrandNodeMark :size="180" :fg="C.signal" :accent="C.carbon" /></div>
<div :style="frame(C.bone)"><BrandNodeMark :size="180" :fg="C.carbon" :accent="C.signal" /></div>
</div>
</div>
<div :style="{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gap: '24px', marginTop: '8px' }">
<div class="logo-caption-row" :style="{ display: 'grid', gap: '24px', marginTop: '8px' }">
<div :style="caption">Primary · on carbon</div>
<div :style="caption">Reversed · on signal</div>
<div :style="caption">Light · on bone</div>
@@ -151,9 +151,9 @@ const doDont: DoDont[] = [
<section :style="{ ...page, background: C.bone }">
<div :style="eyebrow">01.1 · Anatomy</div>
<h2 :style="h2">Constructed, not drawn.</h2>
<div :style="{ display: 'grid', gridTemplateColumns: '1.3fr 1fr', gap: '64px', alignItems: 'center' }">
<div class="anatomy-grid" :style="{ display: 'grid', gap: '64px', alignItems: 'center' }">
<div :style="frame(C.paper, 520)">
<svg viewBox="0 0 360 360" width="380" height="380">
<svg viewBox="0 0 360 360" width="380" height="380" style="max-width:100%;height:auto;">
<defs>
<pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="rgba(0,0,0,0.05)" stroke-width="0.5" />
@@ -182,14 +182,14 @@ const doDont: DoDont[] = [
</div>
<div>
<h3 :style="h3Style(0)">Geometry</h3>
<table :style="{ width: '100%', borderCollapse: 'collapse', fontFamily: inter, fontSize: '14px' }">
<div :style="{ overflowX: 'auto' }"><table :style="{ width: '100%', borderCollapse: 'collapse', fontFamily: inter, fontSize: '14px' }">
<tbody>
<tr v-for="([k, v], i) in specRows" :key="i" :style="{ borderBottom: `1px solid ${C.fog}` }">
<td :style="{ padding: '12px 0', color: 'rgba(0,0,0,0.55)', width: '40%' }">{{ k }}</td>
<td :style="{ padding: '12px 0', fontFamily: mono, fontSize: '13px' }">{{ v }}</td>
</tr>
</tbody>
</table>
</table></div>
<p :style="pStyle(520, true)">Every measurement is a multiple of the stem weight (7u). Don't redraw the mark — use the master SVG.</p>
</div>
</div>
@@ -199,7 +199,7 @@ const doDont: DoDont[] = [
<section :style="{ ...page, background: C.paper }">
<div :style="eyebrow">01.2 · Clear space · Minimum size</div>
<h2 :style="h2">Give it room.</h2>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '32px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '32px' }">
<div>
<div :style="frame(C.fog, 360)">
<div :style="{ position: 'relative' }">
@@ -212,7 +212,7 @@ const doDont: DoDont[] = [
</div>
<div>
<div :style="frame(C.fog, 360)">
<div :style="{ display: 'flex', alignItems: 'flex-end', gap: '48px' }">
<div :style="{ display: 'flex', alignItems: 'flex-end', gap: '48px', flexWrap: 'wrap', justifyContent: 'center' }">
<div v-for="s in [16, 24, 48, 96]" :key="s" :style="{ textAlign: 'center' }">
<BrandNodeMark :size="s" :fg="C.carbon" :accent="C.signal" />
<div :style="{ fontFamily: mono, fontSize: '10px', color: 'rgba(0,0,0,0.5)', marginTop: '12px' }">{{ s }}px</div>
@@ -230,15 +230,15 @@ const doDont: DoDont[] = [
<div :style="eyebrow">01.3 · Wordmark · Lockup</div>
<h2 :style="h2">Letters set in JetBrains Mono.</h2>
<div :style="frame(C.paper, 300)">
<div :style="{ fontFamily: mono, fontWeight: 600, fontSize: '140px', letterSpacing: '-0.04em', color: C.carbon, lineHeight: 1 }">dezky</div>
<div :style="{ fontFamily: mono, fontWeight: 600, fontSize: 'clamp(48px, 15vw, 140px)', letterSpacing: '-0.04em', color: C.carbon, lineHeight: 1 }">dezky</div>
</div>
<div :style="caption">Wordmark · 100% scale</div>
<h3 :style="h3Style()">Horizontal lockup</h3>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '24px' }">
<div :style="frame(C.paper, 220)"><BrandNodeLockup :scale="1.4" :fg="C.carbon" :accent="C.signal" /></div>
<div :style="frame(C.carbon, 220)"><BrandNodeLockup :scale="1.4" :fg="C.carbon" :accent="C.signal" :wordmark="C.bone" /></div>
</div>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px', marginTop: '8px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '24px', marginTop: '8px' }">
<div :style="caption">Light surface</div>
<div :style="caption">Dark surface</div>
</div>
@@ -249,7 +249,7 @@ const doDont: DoDont[] = [
<section :style="{ ...page, background: C.paper }">
<div :style="eyebrow">01.4 · Do · Don't</div>
<h2 :style="h2">How not to use it.</h2>
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '20px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 200px), 1fr))', gap: '20px' }">
<div v-for="(row, i) in doDont" :key="i">
<div :style="{ background: row.bg, borderRadius: '4px', height: '180px', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', overflow: 'hidden' }">
<div :style="{ transform: row.transform || 'none' }">
@@ -272,7 +272,7 @@ const doDont: DoDont[] = [
<div :style="eyebrow">02 · Color</div>
<h1 :style="h1">Two colors do the work.</h1>
<p :style="pStyle(560, true)">Carbon and Signal carry the brand. Everything else is supporting cast. Signal is loud — reserve it for the mark, the node-dot, and primary calls to action. Never tint, never gradient.</p>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px', marginTop: '80px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '24px', marginTop: '80px' }">
<div v-for="c in bigSwatches" :key="c.name">
<div :style="{ background: c.hex, height: '280px', borderRadius: '4px', display: 'flex', alignItems: 'flex-end', padding: '24px', color: c.dark ? C.bone : C.carbon, boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.05)' }">
<div :style="{ fontFamily: tight, fontWeight: 600, fontSize: '36px', letterSpacing: '-0.02em' }">{{ c.name }}</div>
@@ -285,7 +285,7 @@ const doDont: DoDont[] = [
</div>
</div>
<h3 :style="h3Style()">Surfaces & type</h3>
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '16px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 200px), 1fr))', gap: '16px' }">
<div v-for="c in surfaces" :key="c.name">
<div :style="{ background: c.hex, height: '140px', borderRadius: '4px', boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.05)' }" />
<div :style="{ marginTop: '12px' }">
@@ -296,7 +296,7 @@ const doDont: DoDont[] = [
</div>
</div>
<h3 :style="h3Style()">Semantic</h3>
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '16px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 200px), 1fr))', gap: '16px' }">
<div v-for="c in semantic" :key="c.name">
<div :style="{ background: c.hex, height: '140px', borderRadius: '4px', boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.05)' }" />
<div :style="{ marginTop: '12px' }">
@@ -313,7 +313,7 @@ const doDont: DoDont[] = [
<div :style="eyebrow">02.1 · Color in use</div>
<h2 :style="h2">The 70 · 20 · 10 rule.</h2>
<p :style="pStyle(560, true)"><b>70%</b> Bone / Paper · <b>20%</b> Carbon · <b>10%</b> Signal. Surface stays calm; the brand interrupts only at moments of consequence.</p>
<div :style="{ display: 'grid', gridTemplateColumns: '7fr 2fr 1fr', gap: '4px', height: '80px', marginTop: '32px' }">
<div class="color-ratio-bar" :style="{ display: 'grid', gap: '4px', height: '80px', marginTop: '32px' }">
<div :style="{ background: C.paper, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: mono, fontSize: '11px', color: 'rgba(0,0,0,0.5)' }">70 · paper / bone</div>
<div :style="{ background: C.carbon, color: C.bone, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: mono, fontSize: '11px' }">20 · carbon</div>
<div :style="{ background: C.signal, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: mono, fontSize: '11px', color: C.carbon }">10</div>
@@ -325,9 +325,9 @@ const doDont: DoDont[] = [
<div :style="eyebrow">03 · Typography</div>
<h1 :style="h1">Inter Tight for voice. JetBrains Mono for evidence.</h1>
<p :style="pStyle(620, true)">Inter Tight carries the brand's confident, modern register used for everything from hero copy to subheadings. JetBrains Mono is reserved for the wordmark, labels, code, data, and quantitative details anywhere the brand wants to feel exact.</p>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '48px', marginTop: '80px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '48px', marginTop: '80px' }">
<div>
<div :style="{ background: C.fog, borderRadius: '4px', padding: '48px 32px', fontFamily: tight, fontWeight: 500, fontSize: '220px', lineHeight: 0.9, letterSpacing: '-0.04em', color: C.carbon }">Aa</div>
<div :style="{ background: C.fog, borderRadius: '4px', padding: '48px 32px', fontFamily: tight, fontWeight: 500, fontSize: 'clamp(80px, 18vw, 220px)', lineHeight: 0.9, letterSpacing: '-0.04em', color: C.carbon }">Aa</div>
<div :style="{ marginTop: '24px' }">
<div :style="{ fontFamily: tight, fontWeight: 600, fontSize: '24px', letterSpacing: '-0.02em' }">Inter Tight</div>
<div :style="{ fontFamily: mono, fontSize: '11px', color: 'rgba(0,0,0,0.5)', marginTop: '4px' }">Display · UI · prose · 400 · 500 · 600 · 700</div>
@@ -335,7 +335,7 @@ const doDont: DoDont[] = [
</div>
</div>
<div>
<div :style="{ background: C.fog, borderRadius: '4px', padding: '48px 32px', fontFamily: mono, fontWeight: 500, fontSize: '220px', lineHeight: 0.9, letterSpacing: '-0.04em', color: C.carbon }">Aa</div>
<div :style="{ background: C.fog, borderRadius: '4px', padding: '48px 32px', fontFamily: mono, fontWeight: 500, fontSize: 'clamp(80px, 18vw, 220px)', lineHeight: 0.9, letterSpacing: '-0.04em', color: C.carbon }">Aa</div>
<div :style="{ marginTop: '24px' }">
<div :style="{ fontFamily: tight, fontWeight: 600, fontSize: '24px', letterSpacing: '-0.02em' }">JetBrains Mono</div>
<div :style="{ fontFamily: mono, fontSize: '11px', color: 'rgba(0,0,0,0.5)', marginTop: '4px' }">Wordmark · code · labels · 400 · 500 · 600</div>
@@ -350,7 +350,7 @@ const doDont: DoDont[] = [
<div :style="eyebrow">03.1 · Scale</div>
<h2 :style="h2">One scale, ratio 1.25.</h2>
<div :style="{ display: 'flex', flexDirection: 'column', gap: '18px' }">
<div v-for="r in typeScale" :key="r.token" :style="{ display: 'grid', gridTemplateColumns: '120px 80px 1fr 1fr', gap: '24px', alignItems: 'baseline', borderBottom: `1px solid ${C.fog}`, paddingBottom: '14px' }">
<div v-for="r in typeScale" :key="r.token" class="type-scale-row" :style="{ display: 'grid', gap: '24px', alignItems: 'baseline', borderBottom: `1px solid ${C.fog}`, paddingBottom: '14px' }">
<div :style="{ fontFamily: mono, fontSize: '11px', color: 'rgba(0,0,0,0.5)' }">{{ r.token }}</div>
<div :style="{ fontFamily: mono, fontSize: '11px', color: 'rgba(0,0,0,0.5)' }">{{ r.px }} / {{ Math.round(r.px * 1.25) }}</div>
<div :style="{ fontFamily: tight, fontWeight: r.weight, fontSize: `${Math.min(r.px, 40)}px`, letterSpacing: r.px > 40 ? '-0.025em' : '-0.01em', lineHeight: 1 }">dezky</div>
@@ -364,7 +364,7 @@ const doDont: DoDont[] = [
<div :style="eyebrow">04 · Voice</div>
<h1 :style="h1">Direct. Lowercase. Earned.</h1>
<p :style="pStyle(620, true)">dezky doesn't shout — it ships. Sentences are short, verbs do the work, and we talk about sovereignty in plain terms. No exclamation points, no emoji, no AI metaphors, no fear-mongering.</p>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '32px', marginTop: '80px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '32px', marginTop: '80px' }">
<div>
<div :style="{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '20px' }">
<div :style="{ width: '18px', height: '18px', borderRadius: '999px', background: C.ok, color: '#fff', fontSize: '11px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 700 }">✓</div>
@@ -385,7 +385,7 @@ const doDont: DoDont[] = [
</div>
</div>
<h3 :style="h3Style()">Tone shifts by surface</h3>
<table :style="{ width: '100%', borderCollapse: 'collapse', fontFamily: inter }">
<div :style="{ overflowX: 'auto' }"><table :style="{ width: '100%', borderCollapse: 'collapse', fontFamily: inter }">
<thead>
<tr :style="{ borderBottom: `1px solid ${C.carbon}` }">
<th v-for="hh in ['Surface', 'Tone', 'Example']" :key="hh" :style="{ textAlign: 'left', padding: '12px 0', fontSize: '11px', fontFamily: mono, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'rgba(0,0,0,0.55)' }">{{ hh }}</th>
@@ -398,7 +398,7 @@ const doDont: DoDont[] = [
<td :style="{ padding: '14px 0', fontFamily: inter, fontSize: '14px' }">{{ row[2] }}</td>
</tr>
</tbody>
</table>
</table></div>
</section>
<!-- 05 · APPLICATIONS -->
@@ -406,14 +406,14 @@ const doDont: DoDont[] = [
<div :style="eyebrow">05 · Applications</div>
<h1 :style="h1">In the world.</h1>
<p :style="pStyle(560, true)">Reference renders across the surfaces dezky lives on. Treat them as the canonical reductions of the system.</p>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px', marginTop: '64px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '24px', marginTop: '64px' }">
<div :style="frame(C.carbon, 420)">
<div :style="{ width: '220px', height: '220px', background: C.carbon, borderRadius: '50px', boxShadow: '0 24px 80px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.04)', display: 'flex', alignItems: 'center', justifyContent: 'center' }">
<div :style="{ width: 'min(100%, 220px)', height: '220px', background: C.carbon, borderRadius: '50px', boxShadow: '0 24px 80px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.04)', display: 'flex', alignItems: 'center', justifyContent: 'center' }">
<BrandNodeMark :size="170" :fg="C.carbon" :accent="C.signal" />
</div>
</div>
<div :style="frame(C.paper, 420)">
<div :style="{ display: 'flex', alignItems: 'center', gap: '48px' }">
<div :style="{ display: 'flex', alignItems: 'center', gap: '48px', flexWrap: 'wrap', justifyContent: 'center' }">
<div v-for="s in [64, 32, 16]" :key="s" :style="{ textAlign: 'center' }">
<BrandNodeMark :size="s" :fg="C.carbon" :accent="C.signal" />
<div :style="{ fontFamily: mono, fontSize: '10px', color: 'rgba(0,0,0,0.5)', marginTop: '14px' }">{{ s }} × {{ s }}</div>
@@ -421,7 +421,7 @@ const doDont: DoDont[] = [
</div>
</div>
</div>
<div :style="{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px', marginTop: '8px' }">
<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))', gap: '24px', marginTop: '8px' }">
<div :style="caption">iOS app icon · 1024 master</div>
<div :style="caption">Favicon set</div>
</div>
@@ -431,16 +431,16 @@ const doDont: DoDont[] = [
<section :style="{ ...page, background: C.bone }">
<div :style="eyebrow">05.1 · Web</div>
<h2 :style="h2">Marketing hero.</h2>
<div :style="{ background: C.carbon, borderRadius: '8px', padding: '64px 56px', color: C.bone, boxShadow: '0 24px 80px rgba(0,0,0,0.2)' }">
<div :style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '80px' }">
<div :style="{ background: C.carbon, borderRadius: '8px', padding: 'clamp(32px, 5vw, 64px) clamp(20px, 4vw, 56px)', color: C.bone, boxShadow: '0 24px 80px rgba(0,0,0,0.2)' }">
<div :style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '80px', flexWrap: 'wrap', gap: '16px' }">
<BrandNodeLockup :scale="0.7" :fg="C.carbon" :accent="C.signal" :wordmark="C.bone" />
<div :style="{ display: 'flex', gap: '28px', alignItems: 'center', fontFamily: mono, fontSize: '12px', color: 'rgba(255,255,255,0.65)' }">
<div :style="{ display: 'flex', gap: '28px', alignItems: 'center', fontFamily: mono, fontSize: '12px', color: 'rgba(255,255,255,0.65)', flexWrap: 'wrap' }">
<span>product</span><span>security</span><span>pricing</span><span>log in</span>
<span :style="{ background: C.signal, color: C.carbon, padding: '6px 14px', borderRadius: '4px', fontWeight: 600 }">book a demo</span>
</div>
</div>
<div :style="{ fontFamily: mono, fontSize: '12px', color: C.signal, letterSpacing: '0.08em' }">// sovereign productivity · v1.0</div>
<h1 :style="{ fontFamily: tight, fontWeight: 600, fontSize: '92px', letterSpacing: '-0.035em', lineHeight: 0.95, margin: '24px 0', maxWidth: '1000px' }">
<h1 :style="{ fontFamily: tight, fontWeight: 600, fontSize: 'clamp(36px, 8vw, 92px)', letterSpacing: '-0.035em', lineHeight: 0.95, margin: '24px 0', maxWidth: '1000px' }">
Your digital workplace.<br>
<span :style="{ color: C.signal }">Data that stays in the EU.</span>
</h1>
@@ -452,16 +452,16 @@ const doDont: DoDont[] = [
<section :style="{ ...page, background: C.paper }">
<div :style="eyebrow">05.2 · Social</div>
<h2 :style="h2">Avatars & headers.</h2>
<div :style="{ display: 'grid', gridTemplateColumns: '180px 1fr', gap: '24px', alignItems: 'start' }">
<div class="social-grid" :style="{ display: 'grid', gap: '24px', alignItems: 'start' }">
<div>
<div :style="{ width: '180px', height: '180px', borderRadius: '50%', background: C.carbon, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.05)' }">
<div :style="{ width: 'min(100%, 180px)', height: '180px', borderRadius: '50%', background: C.carbon, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.05)' }">
<BrandNodeMark :size="130" :fg="C.carbon" :accent="C.signal" />
</div>
<div :style="caption">Avatar · circular crop</div>
</div>
<div>
<div :style="{ height: '320px', background: C.signal, borderRadius: '8px', position: 'relative', overflow: 'hidden', display: 'flex', alignItems: 'center', padding: '0 64px' }">
<div :style="{ fontFamily: tight, fontWeight: 600, fontSize: '88px', letterSpacing: '-0.035em', lineHeight: 0.95, color: C.carbon, maxWidth: '60%' }">your data<br>stays home.</div>
<div :style="{ fontFamily: tight, fontWeight: 600, fontSize: 'clamp(36px, 8vw, 88px)', letterSpacing: '-0.035em', lineHeight: 0.95, color: C.carbon, maxWidth: '60%' }">your data<br>stays home.</div>
<div :style="{ position: 'absolute', right: '64px', top: '50%', transform: 'translateY(-50%)' }">
<BrandNodeMark :size="220" :fg="C.signal" :accent="C.carbon" />
</div>
@@ -472,10 +472,10 @@ const doDont: DoDont[] = [
</section>
<!-- Closing -->
<section :style="{ background: C.carbon, color: C.bone, padding: '120px 80px', minHeight: '60vh', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }">
<section :style="{ background: C.carbon, color: C.bone, padding: 'clamp(56px, 8vw, 120px) clamp(20px, 5vw, 80px)', minHeight: '60vh', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }">
<div>
<div :style="eyebrow">End</div>
<h1 :style="{ fontFamily: tight, fontWeight: 600, fontSize: '96px', letterSpacing: '-0.04em', lineHeight: 0.95, margin: '24px 0 0', maxWidth: '900px' }">
<h1 :style="{ fontFamily: tight, fontWeight: 600, fontSize: 'clamp(28px, 10vw, 96px)', letterSpacing: '-0.04em', lineHeight: 0.95, margin: '24px 0 0', maxWidth: '900px' }">
Use it well.<br>
<span :style="{ color: C.signal }">Don't redraw it.</span>
</h1>
@@ -486,3 +486,69 @@ const doDont: DoDont[] = [
</section>
</div>
</template>
<style scoped>
/* 01 Logo — 2fr 1fr main grid */
.logo-main-grid {
grid-template-columns: 2fr 1fr;
}
@media (max-width: 768px) {
.logo-main-grid {
grid-template-columns: 1fr;
}
}
/* 01 Logo — 2fr 1fr 1fr caption row */
.logo-caption-row {
grid-template-columns: 2fr 1fr 1fr;
}
@media (max-width: 768px) {
.logo-caption-row {
grid-template-columns: 1fr;
}
}
/* 01.1 Anatomy — 1.3fr 1fr grid */
.anatomy-grid {
grid-template-columns: 1.3fr 1fr;
}
@media (max-width: 768px) {
.anatomy-grid {
grid-template-columns: 1fr;
}
}
/* 02.1 Color ratio bar — 7fr 2fr 1fr */
.color-ratio-bar {
grid-template-columns: 7fr 2fr 1fr;
}
@media (max-width: 768px) {
.color-ratio-bar {
grid-template-columns: 1fr;
height: auto;
}
.color-ratio-bar > div {
min-height: 48px;
}
}
/* 03.1 Type scale rows — 120px 80px 1fr 1fr */
.type-scale-row {
grid-template-columns: 120px 80px 1fr 1fr;
}
@media (max-width: 768px) {
.type-scale-row {
grid-template-columns: 1fr;
}
}
/* 05.2 Social — 180px 1fr */
.social-grid {
grid-template-columns: 180px 1fr;
}
@media (max-width: 768px) {
.social-grid {
grid-template-columns: 1fr;
}
}
</style>