/* ═══════════════════════════════════════════════════════════════
   Osmoti v2 landing. Shared core.
   Visual language taken from the loop section: full-bleed painterly
   color, one two-tone sentence per section, white cards at 3px,
   mono micro-type. Motion follows Emil's rules, noted inline.
   ═══════════════════════════════════════════════════════════════ */

:root {
  --paper: #fff;
  --paper-2: #f7f7f6;
  --ink: #0a0a0a;
  --ink-2: rgba(10,10,10,.56);
  --ink-3: rgba(10,10,10,.26);
  --line: rgba(10,10,10,.10);
  --accent: #0b72a8;
  --brand:  #2abbff;   /* the logo cyan, sampled from mark-640.png */
  --accent-lt: #12a0e0;
  --r: 3px;                                  /* shape lock, from the loop section */
  --pad: 44px;
  --max: 1320px;
  /* CSS built-ins are too weak. these are the two curves the whole site uses. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-io: cubic-bezier(0.77, 0, 0.175, 1);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* Wide displays. The layout is designed at 1320px; past ~1500px the page
   scales up as a whole so it fills a monitor instead of sitting in a strip
   down the middle. Media queries read the real viewport, so breakpoints and
   the mobile nav are unaffected. */
@media (min-width: 1500px) { html { zoom: 1.12; } }
@media (min-width: 1700px) { html { zoom: 1.24; } }
@media (min-width: 1900px) { html { zoom: 1.36; } }
@media (min-width: 2200px) { html { zoom: 1.55; } }
@media (min-width: 2500px) { html { zoom: 1.75; } }
@media (min-width: 3000px) { html { zoom: 2.1; } }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: 'Geist', system-ui, -apple-system, sans-serif; font-weight: 400;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
img { max-width: 100%; }
/* The lockup is 192x127, a ratio that does not reduce to whole numbers at 24 or
   34 pixels, so the integer width/height attributes were squashing it by about
   2%. The attributes still reserve space before load; height:auto hands the
   final shape back to the file. */
.brand img, .pmark, .vision img { height: auto; }
a { color: inherit; text-decoration: none; }
::selection { background: rgba(11,114,168,.18); }

.in { max-width: var(--max); margin: 0 auto; padding: 0 var(--pad); }
.sec { padding: 96px 0; }
.sec-tight { padding: 72px 0; }

/* ── type ─────────────────────────────────────────── */
/* the two-tone sentence: bold statement, then the rest in grey. */
.tt { font-weight: 400; letter-spacing: -.022em; line-height: 1.05; margin: 0; color: var(--ink-3); }
.tt b { font-weight: 400; color: var(--ink); }
/* the brand name inside a two-tone headline, so it does not sit in the grey */
.tt em { font-style: normal; color: var(--brand); }
.onfield .tt em { color: #7fd0f5; }   /* lifted for contrast on the color fields */
/* balance the inner-page h1s: results was leaving "days." alone on a second
   line at 1440. The homepage hero opts out below, because balancing it breaks
   "Your calendar, filled." in half to even the lines. */
h1.tt { font-size: clamp(32px, 4.5vw, 64px); text-wrap: balance; }
.hero-h h1.tt { text-wrap: wrap; }
/* section headings are statements, not promises: even lines read better and
   there is no single phrase that must survive intact */
h2.tt { font-size: clamp(28px, 3.1vw, 44px); text-wrap: balance; }
.onfield .tt { color: rgba(255,255,255,.74); }
.onfield .tt b { color: #fff; }

.lede { font-size: 17px; line-height: 1.62; color: var(--ink-2); max-width: 58ch; margin: 22px 0 0;
  text-wrap: pretty; }
.onfield .lede { color: rgba(255,255,255,.8); }

.micro { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11.5px; letter-spacing: .045em;
  color: var(--ink-2); margin: 0; display: flex; gap: 9px 28px; flex-wrap: wrap; }
.onfield .micro { color: rgba(255,255,255,.7); }
.mono { font-family: 'Geist Mono', ui-monospace, monospace; }

/* ── buttons ──────────────────────────────────────── */
.btn { display: inline-flex; align-items: center; justify-content: center; white-space: nowrap;
  font-size: 15px; font-weight: 400; padding: 15px 28px; border-radius: 999px; border: 0; cursor: pointer;
  font-family: inherit; background: var(--ink); color: #fff;
  transition: transform .16s var(--ease-out), background-color .16s var(--ease-out); }
.btn-sm { font-size: 13.5px; padding: 10px 20px; }
.btn-ghost { background: transparent; color: var(--ink); border: 1px solid var(--line); }
.onfield .btn { background: #fff; color: var(--ink); }
.onfield .btn-ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,.4); }
.btn:active { transform: scale(0.97); }        /* the interface has to feel like it heard you */
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.alt { font-size: 14.5px; color: var(--ink-2); margin-left: 20px; }
.onfield .alt { color: rgba(255,255,255,.74); }
@media (hover: hover) and (pointer: fine) {
  .btn:hover { transform: translateY(-1px); }
}

/* ── nav ──────────────────────────────────────────── */
.nav { position: sticky; top: 0; z-index: 60; background: var(--paper);
  transition: box-shadow .2s var(--ease-out), background-color .2s var(--ease-out); }
.nav.onfield { background: transparent; }
.nav.stuck { box-shadow: 0 1px 0 var(--line); background: rgba(255,255,255,.86);
  backdrop-filter: blur(14px) saturate(1.2); }
.nav.onfield.stuck { background: rgba(10,20,28,.6); box-shadow: 0 1px 0 rgba(255,255,255,.14); }
.navin { max-width: var(--max); margin: 0 auto; padding: 0 var(--pad);
  height: 72px; display: flex; align-items: center; justify-content: space-between; }
.brand { display: flex; align-items: center; gap: 9px; }
.brand img { width: 24px; display: block; }
.brand b { font-size: 14px; font-weight: 500; letter-spacing: .13em; }
.onfield .brand b { color: #fff; }
.nl { display: flex; gap: 28px; font-size: 14.5px; color: var(--ink-2); }
.onfield .nl { color: rgba(255,255,255,.76); }
.nl a { position: relative; padding-bottom: 2px; }
.nl a::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform .18s var(--ease-out); }
@media (hover: hover) and (pointer: fine) { .nl a:hover::after { transform: scaleX(1); } }
/* the page you are on, marked in the nav rather than only in the markup */
.nl a[aria-current="page"] { color: var(--ink); }
.nl a[aria-current="page"]::after { transform: scaleX(1); }

/* On desktop the wrapper must not exist as a box, or it becomes a single flex
   item and the links stop sitting between the brand and the button. */
.navmenu { display: contents; }
.burger, .navfoot { display: none; }

/* three bars from one span, crossing into an X. 44px box for the target,
   negative margin so the bars still line up with the container edge. */
.burger { width: 44px; height: 44px; margin-right: -11px; padding: 0; border: 0;
  background: none; color: var(--ink); cursor: pointer;
  align-items: center; justify-content: center; }
.burger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r); }
.burger .bar { position: relative; display: block; width: 21px; height: 1.5px;
  background: currentColor; border-radius: 2px;
  transition: background-color .12s linear .12s; }
.burger .bar::before, .burger .bar::after { content: ''; position: absolute; left: 0;
  width: 21px; height: 1.5px; background: currentColor; border-radius: 2px;
  transition: transform .28s var(--ease-io); }
.burger .bar::before { top: -6.5px; }
.burger .bar::after { top: 6.5px; }
.nav.open .burger .bar { background: transparent; transition: background-color .12s linear; }
.nav.open .burger .bar::before { transform: translateY(6.5px) rotate(45deg); }
.nav.open .burger .bar::after { transform: translateY(-6.5px) rotate(-45deg); }

/* ── painterly field ──────────────────────────────── */
.field { position: relative; overflow: hidden; isolation: isolate; }
.field > * { position: relative; z-index: 2; }
.field .cloud { position: absolute; inset: -16%; z-index: 0; pointer-events: none; background-size: cover;
  will-change: transform; }
/* At panel scale the loop section runs these at .62/.55. A full-bleed field is
   6x the area, and at that size the same opacity stops reading as paint and
   starts reading as fog. Same recipe, much lighter hand. */
.field .c1 { mix-blend-mode: screen; opacity: .26;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.009' numOctaves='6' seed='5'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1.4 0 0 0 -0.42'/%3E%3C/filter%3E%3Crect width='900' height='900' filter='url(%23a)'/%3E%3C/svg%3E"); }
.field .c2 { mix-blend-mode: multiply; opacity: .3;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='b'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013' numOctaves='5' seed='23'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.3 0 0 0 -0.5'/%3E%3C/filter%3E%3Crect width='900' height='900' filter='url(%23b)'/%3E%3C/svg%3E"); }
/* ambient drift. transform only, so it runs off the main thread and never
   competes with scrolling. 68s and 92s so the two layers never resync. */
.field .c1 { animation: drift1 68s linear infinite; }
.field .c2 { animation: drift2 92s linear infinite; }
@keyframes drift1 { 0% { transform: translate3d(0,0,0) scale(1.02); }
  50% { transform: translate3d(2.2%, -1.6%, 0) scale(1.06); }
  100% { transform: translate3d(0,0,0) scale(1.02); } }
@keyframes drift2 { 0% { transform: translate3d(0,0,0) scale(1.04); }
  50% { transform: translate3d(-2.6%, 1.4%, 0) scale(1.01); }
  100% { transform: translate3d(0,0,0) scale(1.04); } }
.field .scr { position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(96deg, rgba(8,12,18,.52) 0%, rgba(8,12,18,.3) 44%, rgba(8,12,18,.05) 76%); }

.f-amber { background: radial-gradient(115% 130% at 14% 6%, #f0bd42, #c8830f 52%, #9a6408); }
.f-blue  { background: radial-gradient(115% 130% at 14% 6%, #16a6e6, #0a5f96 56%, #063a60); }
.f-sage  { background: radial-gradient(115% 130% at 14% 6%, #55886f, #2c5344 58%, #1b352c); }
/* not grey. a deep teal-black so it belongs to the blue rather than sitting outside it. */
.f-ink   { background: radial-gradient(125% 135% at 15% 4%, #1b4257, #0a1d2b 56%, #050b11); }
.f-sweep { background: linear-gradient(104deg, #d99c22 0%, #a96e0a 24%, #0f7fb6 58%, #0a5f96 76%, #2b5344 100%); }

/* A light field. The campaigns band ran f-blue, which put two saturated blues
   close together with only the white loop and spine sections between them, and
   the sequence now alternates instead: bright cyan diagram, light band here,
   f-ink, f-blue.

   Cloud comes almost entirely off the multiply layer, the reverse of the
   diagram's wash. On a near-white ground a white screen layer has nothing to
   lift, so the weather has to be painted in shadow rather than in highlight.
   Same turbulence, frequencies, seeds and drift as every other band; measured
   spread 22.5 L* against f-blue's 24.3, with the ground still at a mean of 82.

   Cyan rather than black, again: black noise on a light ground reads as grey
   dirt. No `onfield` on the section, so the headline, the post borders and the
   caption all return to the same dark-on-light they use on every white
   section. */
.f-mist { background:
    radial-gradient(70% 85% at 3% -6%,   rgba(42,187,255,.24), transparent 62%),
    radial-gradient(60% 72% at 98% 106%, rgba(11,114,168,.15), transparent 66%),
    linear-gradient(180deg, #eaf6ff, #cde8fa); }
.f-mist .c1 { opacity: .22; }
.f-mist .c2 { opacity: 1;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='m' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013' numOctaves='5' seed='23'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.14 0 0 0 0 0.54 0 0 0 0 0.78 1.3 0 0 0 -0.5'/%3E%3C/filter%3E%3Crect width='900' height='900' filter='url(%23m)'/%3E%3C/svg%3E"); }

/* A slate field for the facts table. The fourth blue and the last one: the
   diagram is the brand cyan, the campaigns band is a pale mist, the identity
   band is the deep saturated f-blue, and this is a grey-blue in the middle of
   the range, desaturated so a table of small print stays comfortably
   dark-on-light. Same two turbulence layers as every band; the multiply fill
   is a slate rather than a cyan so the weather stays in this band's own key. */
.f-slate { background:
    radial-gradient(70% 85% at 3% -6%,   rgba(96,150,190,.28), transparent 62%),
    radial-gradient(60% 72% at 98% 106%, rgba(40,80,115,.18), transparent 66%),
    linear-gradient(180deg, #c6d8e6, #afc8da); }
.f-slate .c1 { opacity: .35; }
.f-slate .c2 { opacity: .6;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='sl' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013' numOctaves='5' seed='23'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.24 0 0 0 0 0.37 0 0 0 0 0.48 1.3 0 0 0 -0.5'/%3E%3C/filter%3E%3Crect width='900' height='900' filter='url(%23sl)'/%3E%3C/svg%3E"); }
/* On the paint the table goes on a white card, same as every band's content:
   the site's system is painterly ground, white cards on top, and eleven rows
   of small print sitting naked on weather was the one place it broke. */
/* border-collapse makes a table ignore its own padding, which is why the row
   labels sat flush against the card edge: the 26px was being silently dropped.
   Separate borders with zero spacing keep the row rules and let padding work.
   Full container width, because a 940px card on a full-bleed band left a third
   of the weather empty, which is what read as lopsided. */
.f-slate .facts { background: #fff; border-radius: 8px; padding: 10px 28px;
  max-width: none; border-collapse: separate; border-spacing: 0;
  box-shadow: 0 1px 3px rgba(10,40,60,.08), 0 14px 34px rgba(10,40,60,.08); }
.f-slate .facts tr:last-child th, .f-slate .facts tr:last-child td { border-bottom: 0; }
.f-slate .tt { color: rgba(8,32,46,.5); }
@media (max-width: 700px) {
  .f-slate .facts { padding: 6px 18px 10px; }
  .f-slate .facts tr:last-child { border-bottom: 0; }
}

/* ── white card ───────────────────────────────────── */
.w { background: #fff; border: 1px solid var(--line); border-radius: var(--r); padding: 18px 17px; }
.w-lg { padding: 26px 24px; }
.pmark { width: 17px; margin: 0 auto 13px; display: block; opacity: .85; }
.ttl { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .07em;
  text-transform: uppercase; color: rgba(10,10,10,.42); margin: 0 0 8px; }
.chk { display: flex; align-items: center; gap: 9px; border: 1px solid rgba(0,0,0,.11);
  border-radius: 999px; padding: 7px 11px; font-size: 11.5px; color: rgba(10,10,10,.72); margin-bottom: 6px; }
.chk s { width: 11px; height: 11px; border: 1px solid rgba(0,0,0,.28); border-radius: 2px;
  display: block; flex: none; }
.rep-d { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; color: rgba(10,10,10,.45);
  letter-spacing: .04em; margin: 0; }
.rep-h { font-size: 14px; font-weight: 500; margin: 1px 0 2px; }
.met { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px 14px; margin: 12px 0; }
.met span { display: block; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase; color: rgba(10,10,10,.44); }
.met b { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 14px; font-weight: 400; }
.met b.hi { color: var(--accent); font-size: 16px; }
.sum { font-size: 11px; line-height: 1.48; color: rgba(10,10,10,.64); margin: 0; }
.sum em { font-style: normal; color: rgba(10,10,10,.42);
  font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; }
.q { background: rgba(0,0,0,.05); border-radius: var(--r); padding: 9px 11px; font-size: 12.5px;
  line-height: 1.42; color: rgba(10,10,10,.8); }

/* ═══ motion primitives ═══
   one orchestrated moment per section, then the section is still.
   only transform, opacity and clip-path animate. */
/* Scoped to .js, which an inline script in <head> sets before first paint.
   Without it every one of these elements is invisible whenever the script does
   not run: a 404 on site.js, a blocking extension, a parse error. That is the
   whole page gone, so the hiding has to be conditional on the thing that
   un-hides it. */
.js .r { opacity: 0; transform: translateY(11px); }
.r.on { opacity: 1; transform: none;
  transition: opacity .44s var(--ease-out), transform .44s var(--ease-out); }
.js .ph { clip-path: inset(0 0 16% 0); }
.ph.on { clip-path: inset(0 0 0 0); transition: clip-path .66s var(--ease-out); }
/* Adding .on is not enough in a document that is not being rendered: a hidden
   tab does not advance CSS transitions, so opacity stays frozen at the 0 it
   started from. This forces the end state with no transition to run. */
html.instant .r, html.instant .ph {
  opacity: 1 !important; transform: none !important;
  clip-path: none !important; transition: none !important; }

/* ═══ signature 1 · the fifteen minute clock ═══ */
.clock { display: grid; grid-template-columns: 1fr; gap: 0; position: relative; padding-left: 30px; }
.clock .spine { position: absolute; left: 5px; top: 8px; bottom: 26px; width: 2px;
  background: rgba(255,255,255,.24); overflow: hidden; }
.clock .spine i { position: absolute; inset: 0; background: var(--accent-lt); display: block;
  transform: scaleY(0); transform-origin: top;
  transition: transform 1.5s var(--ease-io); }
.clock.on .spine i { transform: scaleY(1); }
.clock .step { position: relative; padding: 0 0 22px; }
.clock .step::before { content: ''; position: absolute; left: -30px; top: 5px; width: 12px; height: 12px;
  border-radius: 50%; background: #fff; box-shadow: 0 0 0 3px rgba(255,255,255,.2);
  transform: scale(0.4); opacity: 0; transition: transform .3s var(--ease-out), opacity .3s var(--ease-out); }
.clock.on .step.lit::before { transform: scale(1); opacity: 1; }
.clock .t { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .05em;
  color: rgba(255,255,255,.6); display: block; margin-bottom: 3px; }
.clock .l { font-size: 16px; color: #fff; line-height: 1.4; }
.clock .step { opacity: 0; transform: translateY(8px); }
.clock.on .step.lit { opacity: 1; transform: none;
  transition: opacity .34s var(--ease-out), transform .34s var(--ease-out); }
.elapsed { display: inline-flex; align-items: baseline; gap: 10px; margin-top: 6px;
  border: 1px solid rgba(255,255,255,.28); border-radius: 999px; padding: 9px 18px; }
.elapsed b { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 20px; font-weight: 400; color: #fff;
  font-variant-numeric: tabular-nums; }
.elapsed span { font-size: 12.5px; color: rgba(255,255,255,.66); }

/* ═══ signature 2 · budget reallocation ═══ */
.alloc { display: grid; gap: 18px; }
.alloc .row { display: grid; grid-template-columns: 88px 1fr 74px; align-items: center; gap: 16px; }
.alloc .k { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ink-2); }
.alloc .track { height: 34px; background: rgba(10,10,10,.06); border-radius: var(--r); overflow: hidden; }
.alloc .fill { height: 100%; border-radius: var(--r); transform-origin: left; transform: scaleX(var(--from));
  transition: transform 1.05s var(--ease-out); }
.alloc.on .fill { transform: scaleX(var(--to)); }
.alloc .fill.meta { background: linear-gradient(90deg, #1288c4, #0b72a8); }
.alloc .fill.google { background: linear-gradient(90deg, #e0a52b, #b0740c); }
.alloc .v { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 15px; text-align: right;
  font-variant-numeric: tabular-nums; }
.journal { margin-top: 26px; border-top: 1px solid var(--line); padding-top: 20px; }
.journal p { margin: 0 0 7px; font-size: 14.5px; line-height: 1.55; color: var(--ink-2); }
.journal p b { color: var(--ink); font-weight: 400; }
.journal .stamp { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.replay { margin-top: 16px; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); background: none; border: 0;
  cursor: pointer; padding: 6px 0; transition: color .16s var(--ease-out); }
.replay:hover { color: var(--accent); }

/* ═══ signature 3 · format-native morph ═══ */
.morph { display: grid; grid-template-columns: 1fr; justify-items: center; }
/* The 1:1 Facebook frame is as wide as the stage is tall, so the stage height
   is what decides whether it fits its column. 520 sits inside the 582px column
   at 1440; the breakpoints below keep it inside the narrower ones. */
.morph .stage { position: relative; width: 100%; height: 520px; display: flex; align-items: center; justify-content: center; }
.morph .frame { position: relative; height: 100%; width: auto; max-width: 100%;
  border-radius: var(--r); overflow: hidden;
  background: rgba(255,255,255,.08);
  box-shadow: 0 2px 6px rgba(0,0,0,.18), 0 26px 60px rgba(0,0,0,.3);
  /* only the width animates, so the frame reshapes instead of the picture stretching */
  transition: width .52s var(--ease-io); }
.morph .frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .3s var(--ease-out), filter .3s var(--ease-out); filter: blur(3px); }
.morph .frame img.live { opacity: 1; filter: blur(0); }   /* blur bridges the swap so it reads as one object */
.morph .chips { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 30px; }
.morph .chip { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10.5px; letter-spacing: .07em;
  text-transform: uppercase; padding: 9px 15px; border-radius: 999px; cursor: pointer;
  background: transparent; color: rgba(255,255,255,.6); border: 1px solid rgba(255,255,255,.24);
  font-family: 'Geist Mono', ui-monospace, monospace;
  transition: color .16s var(--ease-out), border-color .16s var(--ease-out), background-color .16s var(--ease-out); }
.morph .chip[aria-selected="true"] { background: #fff; color: var(--ink); border-color: #fff; }
.morph .chip:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.morph .chip:active { transform: scale(0.97); }
.morph .ratio { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .06em;
  color: rgba(255,255,255,.58); margin-top: 18px; text-align: center; }

/* ═══ the four prohibitions ═══ */
.nevers { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
.nevers li { display: flex; gap: 16px; align-items: baseline; padding: 16px 0;
  border-bottom: 1px solid var(--line); font-size: 16.5px; line-height: 1.5; }
.nevers li:first-child { border-top: 1px solid var(--line); }
.nevers b { font-weight: 400; color: var(--ink); flex: none; width: 78px;
  font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--accent); }
.nevers span { color: var(--ink-2); }
.nevers span em { font-style: normal; color: var(--ink); }

/* ═══ the loop section, kept exactly as it was ═══ */
/* horizontal padding lives on .in, same as every other section, or this one
   sits 53px left of the rest of the page at 1440 */
.s2 { background: #fff; color: var(--ink); padding: 66px 0 24px; border-top: 1px solid var(--line); }
.s2 h2 { font-size: clamp(26px, 3vw, 40px); line-height: 1.05; letter-spacing: -.016em; font-weight: 400;
  text-wrap: balance;
  margin: 0; color: rgba(10,10,10,.24); }
.s2 h2 b { font-weight: 400; color: #0a0a0a; }
.s2 .s2sub { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11.5px; letter-spacing: .045em;
  color: rgba(10,10,10,.5); margin: 18px 0 0; display: flex; gap: 9px 30px; flex-wrap: wrap; }
.trip { display: grid; grid-template-columns: repeat(3, 1fr); margin-top: 42px; }
.pan { position: relative; padding: 26px 16px 16px; overflow: hidden; isolation: isolate; }
.pan::before, .pan::after { content: ''; position: absolute; inset: -12%; pointer-events: none; background-size: cover; }
.pan::before { mix-blend-mode: screen; opacity: .62;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.0055' numOctaves='6' seed='5'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1.4 0 0 0 -0.42'/%3E%3C/filter%3E%3Crect width='500' height='500' filter='url(%23a)'/%3E%3C/svg%3E"); }
.pan::after { mix-blend-mode: multiply; opacity: .55;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cfilter id='b'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.0085' numOctaves='5' seed='23'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.3 0 0 0 -0.5'/%3E%3C/filter%3E%3Crect width='500' height='500' filter='url(%23b)'/%3E%3C/svg%3E"); }
.pan > *, .pan .white { position: relative; z-index: 2; }
.pan.amber { background: radial-gradient(120% 90% at 22% 8%, #e6ad2c, #b0740c 62%, #8a5a06); }
.pan.blue  { background: radial-gradient(120% 90% at 22% 8%, #12a0e0, #0a5f96 60%, #073f66); }
.pan.sage  { background: radial-gradient(120% 90% at 22% 8%, #4d8069, #2c5344 62%, #1e3a30); }
.pan h3 { margin: 0 0 20px; text-align: center; color: #fff; font-size: 19px; font-weight: 400;
  letter-spacing: -.01em; line-height: 1.24; }
.white { background: #fff; border-radius: 3px; padding: 16px 15px; }

/* ── mechanism diagram: paste URL, fork, merge, loop back ────── */
/* The mechanism diagram. Six steps will not fit one row at 1232px, so it runs
   as two rows of a four-column grid: the input and the six channels on top,
   the loop that follows underneath. The flow arrows are pseudo-elements living
   in the grid gap, because as real children they consumed cells and pushed the
   cards into a zigzag. */
/* The diagram sits between the hero and the loop section, both of which are
   white, so on white it read as one continuous page with no edges.

   It is painted --brand (#2abbff), the logo cyan the hero sets "Osmoti" in,
   at that value rather than a tint of it: sampled across the section the ground
   runs hue 199.7-201.0 and L* 58.6-63.1, against the token's 199.2 and 58.2.
   Earlier passes sat at L* 87-95, which shares the hue but is visibly a
   different shade, and the point of the section is that it is the same colour.
   Values spelled out rather than referenced because these are rgba() and the
   token is a hex, same as everywhere else in the sheet that needs it at alpha.

   No borders. At this saturation the ground is its own edge against the white
   above and below, and a 1px line only added a seam. */
.mx-wash {
  position: relative; overflow: hidden; isolation: isolate;
  background:
    radial-gradient(64% 80% at 2% -4%,   rgba(96,208,255,.55), transparent 62%),
    radial-gradient(56% 70% at 99% 104%, rgba(9,150,220,.30), transparent 66%),
    linear-gradient(180deg, #1eb2fa, #02a2ec);
}

/* Foreground on a saturated ground. White fails here, badly: 2.17:1 against
   this cyan, because cyan is a light hue and wants dark type, unlike the deep
   f-blue and f-ink bands that flip to white. So everything stays dark, moved
   off neutral grey into the blue's own family so the two-tone still separates.

   Solid values rather than alphas, because with real cloud the ground is no
   longer one colour: an alpha that clears 4.5:1 against the mean can fail
   against the shadow, and the layers drift, so every part of the ground passes
   under every glyph eventually. These are measured against the darkest and
   lightest 2% of the rendered ground, not its average: ink 6.00:1, the grey
   half 3.87:1 (large text), lede 5.27:1, loop rail 5.66:1. */
.mx-wash .tt   { color: #0b3f57; }
.mx-wash .tt b { color: #041c29; }
.mx-wash .lede { color: #04283a; }
.mx-wash .mx-loop { color: #032230; }
.mx-wash > * { position: relative; z-index: 2; }
/* The same two turbulence layers the colour bands are painted with. What makes
   cloud legible is the spread between the light and dark of it, not the ground
   colour: measured over the section, the f-blue band spans 24.3 L* and this one
   was spanning 11.0, which is why it read as flat next to them. It now spans
   21.6 with the mean still on the brand value.

   Nearly all of that comes off the screen layer, which is why it runs .85 where
   the fields run .26. Getting it from the multiply side instead cut shadows
   down to L* 40, and dark-on-light has a floor the fields' white-on-dark does
   not: at that depth the lede could not clear 4.5:1 anywhere on the section.
   Bright cloud on a deeper base keeps the same texture with the floor intact.

   The multiply layer is painted the logo cyan rather than black, because on a
   light ground black noise reads as grey dirt, not as cloud, and lower in
   lightness than the logo value so it still reads as the shadow side. */
.mx-wash .cloud { position: absolute; inset: -16%; z-index: 0; pointer-events: none;
  background-size: cover; will-change: transform; }
.mx-wash .c1 { mix-blend-mode: screen; opacity: .85;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.009' numOctaves='6' seed='5'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1.4 0 0 0 -0.42'/%3E%3C/filter%3E%3Crect width='900' height='900' filter='url(%23a)'/%3E%3C/svg%3E");
  animation: drift1 68s linear infinite; }
.mx-wash .c2 { mix-blend-mode: multiply; opacity: .55;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='c' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013' numOctaves='5' seed='23'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0.40 0 0 0 0 0.62 1.3 0 0 0 -0.5'/%3E%3C/filter%3E%3Crect width='900' height='900' filter='url(%23c)'/%3E%3C/svg%3E");
  animation: drift2 92s linear infinite; }

.mx { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 30px 26px; margin-top: 44px; }
/* white, so they lift off the wash rather than dissolving into it */
.mx-wash .mx-card { background: #fff; border-color: transparent;
  box-shadow: 0 1px 3px rgba(4,40,60,.10), 0 6px 18px rgba(4,40,60,.06); }
.mx-wash .mx-key  { border-color: rgba(11,114,168,.44); }
.mx-card { position: relative; border: 1px solid var(--line); border-radius: var(--r);
  padding: 22px 22px 24px; background: var(--paper); display: flex; flex-direction: column; }
.mx-key { border-color: rgba(11,114,168,.38); }
.mx-n { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .12em;
  color: var(--ink-3); margin: 0 0 14px; }
.mx-key .mx-n { color: var(--accent); }
.mx-k { font-size: 16px; line-height: 1.3; letter-spacing: -.012em; color: var(--ink); margin: 0 0 9px; }
.mx-d { font-size: 13.5px; line-height: 1.58; color: var(--ink-2); margin: 0; }

/* the six channels, inside step 02 */
.mx-chips { list-style: none; margin: auto 0 0; padding: 16px 0 0; display: flex; flex-wrap: wrap; gap: 6px; }
.mx-chips li { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); border: 1px solid rgba(11,114,168,.3);
  border-radius: 999px; padding: 5px 10px; }

/* row one: the input, then the six channels across the rest */
.mx-start { grid-column: 1; }
.mx-wide  { grid-column: 2 / span 3; }

/* the chevron sits in the gap to the right of a card */
.mx-flow::after { content: ''; position: absolute; top: 50%; right: -20px; width: 13px; height: 13px;
  margin-top: -7px; border-right: 1.6px solid var(--accent-lt); border-top: 1.6px solid var(--accent-lt);
  transform: rotate(45deg); opacity: .8; }

.mx-loop { display: flex; align-items: center; justify-content: center; gap: 9px; margin: 30px 0 0;
  font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10.5px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent); }
.mx-loop svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 1.8; fill: none;
  stroke-linecap: round; }

@media (max-width: 1000px) {
  .mx { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 20px; }
  /* 02 wraps to its own row here, so 01 takes the full width above it rather
     than sitting beside an empty cell with a chevron pointing at nothing */
  .mx-start { grid-column: 1 / span 2; }
  .mx-wide  { grid-column: 1 / span 2; }
  .mx-flow::after { right: -14px; }
  .mx-start::after { display: none; }
  /* in the pairs below, only the left card points at a neighbour */
  .mx-card:nth-of-type(2n)::after { display: none; }
}
@media (max-width: 620px) {
  .mx { grid-template-columns: 1fr; gap: 16px; }
  .mx-start, .mx-wide { grid-column: 1; }
  .mx-flow::after { display: none; }
}

/* The brand kit used to be its own section. It is the same idea as the posts
   above it, one heading apart, and on mobile the pair cost 4.4 screens of the
   19 the page runs to. Merged, with a rule and a label instead of a heading. */
/* no rule and no top padding any more: this is the top of its own section now,
   not a second half bolted to the end of another one */
.kitwrap { margin-top: 0; }
.kw-h { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent); margin: 0; }
.kitwrap .lede { max-width: 54ch; }

/* ── client marks, in the hero ─────────────────────────
   The marks are normalised as assets by scripts/normalize_logos.py: trimmed,
   flattened to one ink, scaled so sqrt(bbox area x ink coverage) matches
   across the set, written at 2x with exact display sizes in the markup. That
   is why there is not a single per-logo rule here, and why a marquee can look
   composed at all: motion magnifies imbalance, and these are balanced before
   CSS ever sees them.

   The marquee is two identical sets translating -50%, pure CSS. The second
   set is aria-hidden with untabbable links, so a screen reader or keyboard
   user meets each company exactly once. It pauses on hover and on keyboard
   focus, because a link that moves under a pointer or a focus ring is not a
   link, it is a fairground game. Under reduced motion the duplicate set is
   dropped entirely and the real one wraps as a static left-aligned grid,
   which is the same layout this row had before it moved.

   Every image declares width and height, and the marquee's height is its
   tallest mark plus padding at every viewport, so nothing shifts on load. */
.clients { margin-top: 34px; border-top: 1px solid var(--line); padding-top: 20px; }
.cl-cap { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3);
  margin: 0 0 16px; }
.cl-marquee { overflow: hidden; padding: 2px 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
.cl-track { display: flex; width: max-content; animation: cl-scroll 44s linear infinite; }
/* gap and padding-right must stay equal or the loop stutters at the seam */
.cl-set { display: flex; align-items: center; gap: 58px; padding-right: 58px; flex: 0 0 auto; }
.cl-mark { display: inline-flex; align-items: center; flex: 0 0 auto; }
.cl-mark img { display: block; max-width: 100%; height: auto;
  opacity: .40; transition: opacity .24s var(--ease-out); }
.cl-mark:hover img, .cl-mark:focus-visible img { opacity: .78; }
.cl-mark:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px;
  border-radius: var(--r); }
.cl-marquee:hover .cl-track,
.cl-marquee:focus-within .cl-track { animation-play-state: paused; }
@keyframes cl-scroll { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }

@media (max-width: 760px) {
  .clients { margin-top: 28px; padding-top: 18px; }
  .cl-cap { margin-bottom: 14px; }
  .cl-set { gap: 40px; padding-right: 40px; }
  .cl-track { animation-duration: 34s; }
}

@media (prefers-reduced-motion: reduce) {
  .cl-track { width: auto; animation: none; }
  /* flex-basis must release to 100% or the set stays sized to its content and
     never wraps: flex-wrap on a max-content box is a no-op */
  .cl-set { flex: 1 1 100%; width: 100%;
    flex-wrap: wrap; justify-content: flex-start; gap: 22px 40px; padding-right: 0; }
  .cl-set[aria-hidden="true"] { display: none; }
  .cl-marquee { mask-image: none; -webkit-mask-image: none; }
}

/* ── the stack row, on how-it-works ───────────────────
   Named, not logo'd. The previous site had these as favicons scraped from each
   vendor's domain, 32 to 64px, which is fine as a browser-tab icon and mush at
   any size a logo strip needs. Set in type they stay sharp, stay on this
   site's grid, and carry the category, which is the part an owner is actually
   checking for. */
.stk { list-style: none; margin: 32px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.stk-chip { background: var(--paper); padding: 15px 17px 16px; display: flex;
  flex-direction: column; gap: 3px; }
.stk-chip b { font-size: 14.5px; font-weight: 500; color: var(--ink); letter-spacing: -.008em; }
.stk-chip span { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
@media (max-width: 900px) { .stk { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 620px) { .stk { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ── the four quiet channels ──────────────────────────
   Social had three sections on this page and local search, AI answers, reviews
   and rebooking had none, which is what made the page read ads-and-social-first
   when the product is six channels. Each card shows its channel in the format
   that channel actually appears in, so the point lands without a caption. */
/* The brand section, on the ink field. It used to be the tail of the six
   channel section and the format-native band was a third statement about
   creative sitting on its own. One section now: the kit, the kit applied, and
   the same creative rebuilt per surface, which is one idea in three steps. */
.brandtwo { margin-top: 60px; align-items: center; }
/* the format column had an eyebrow and two paragraphs of body and nothing with
   any weight, so beside a 520px picture it read as a caption that had drifted */
.sub-h { font-size: clamp(21px, 2.2vw, 29px); line-height: 1.14; letter-spacing: -.018em;
  font-weight: 400; color: var(--ink); margin: 13px 0 16px; max-width: 17ch; text-wrap: balance; }
.lede.sm { font-size: 15px; margin-top: 20px; }

/* The brand section is white now: three colour bands ran back to back before
   it, and this is the one of the three that does not need paint to work. The
   morph was built for the ink field, so its frame, chips and caption are
   re-pitched for light here, scoped to the section because how-it-works still
   runs the component on f-ink. */
#brand .morph .frame { background: var(--paper-2);
  box-shadow: 0 2px 6px rgba(10,30,45,.10), 0 22px 50px rgba(10,30,45,.13); }
/* Only the border eases. The selected chip goes from dark-on-light to
   light-on-dark, so any duration on the fill or the label means an interval
   where one is part way across and the other is not: ease both and the label
   passes through grey on grey, ease neither and it is legible on every frame.
   The morph re-selects a chip every few seconds, so that interval is not rare. */
#brand .morph .chip { color: var(--ink-2); border-color: rgba(10,10,10,.18);
  transition: border-color .16s var(--ease-out); }
#brand .morph .chip:hover { color: var(--ink); border-color: rgba(10,10,10,.34); }
#brand .morph .chip[aria-selected="true"] { background: var(--ink); color: #fff; border-color: var(--ink); }
#brand .morph .ratio { color: var(--ink-3); }
/* Rahul's focus ring is white, written when every morph sat on a dark field.
   This one is on white now, so the ring takes the ink instead. */
#brand .morph .chip:focus-visible { outline-color: var(--ink); }
.onfield .kw-h { color: #7fd0f5; }

/* All six channels as one peer set. They were two grids under two headings,
   the posts big and the other four small, which said the posts were the
   product and the rest were extras. They are not: four of the six carry the
   same weight and none of them has a feed, which is the only reason they are
   harder to picture.

   Rows stretch. Tried align-items:start first, on the theory that letting each
   card stand at its own height was more honest, and it read worse: the short
   cards floated above the row's baseline, which is itself a way of saying the
   tall ones matter more. Equal-height rows say the opposite. */
/* The creative runs at its native ratio. It was square-cropped to keep the
   post cards from towering over the other four, and the crop cut the work:
   Velora lost its button, Cinder lost the top of its lockup. The grid absorbs
   the height instead: four columns, the two posts span both rows, and the
   four short cards stack in the remaining two columns beside them. Nothing
   is cropped and no card floats over a half-empty row. */
.six { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px 20px; margin-top: 44px; }
/* Square card, every card, no exceptions: the six-channel claim is that none
   of them is the main one, and a card that changes shape says otherwise.
   Cropped from the source, not resized to it. The two campaign posters are
   1003x1568, so the square keeps roughly two thirds of the frame and cuts the
   rest; object-position is picked per image from what is actually in that
   third, not a single value guessed across two different layouts. The site's
   own button sits below the media on every card regardless, so a poster's own
   baked-in CTA is the one safe thing to lose to the crop. */
.six .post { border-radius: 6px; }
.six .post .media { aspect-ratio: 1 / 1; }
.six .post .media img { object-position: center top; }
@media (max-width: 1000px) { .six { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 16px; } }
@media (max-width: 620px)  { .six { grid-template-columns: 1fr; gap: 14px; } }

.chn { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; margin-top: 44px; }
.chncard { border: 1px solid var(--line); border-radius: 8px; background: #fff;
  padding: 16px 15px 15px; display: flex; flex-direction: column; }
.chn-k { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3); margin: 0 0 13px;
  display: flex; flex-direction: column; gap: 3px; }
.chn-k span { color: var(--accent); }
.chn-body { flex: 1; display: flex; flex-direction: column; gap: 11px; }
.chn-note { font-size: 12.5px; line-height: 1.5; color: var(--ink-2); margin: 14px 0 0;
  padding-top: 12px; border-top: 1px solid var(--line); }

/* local search */
.srch-rank { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 -3px; }
/* the results underneath are what make "top" mean anything, and they fill the
   card, which was running a third shorter than the post cards beside it */
.srch-rest { list-style: none; margin: 2px 0 0; padding: 0; }
.srch-rest li { padding: 8px 2px; border-top: 1px solid var(--line); opacity: .5; }
.srch-rest b { display: block; font-size: 12px; font-weight: 400; color: var(--ink); letter-spacing: -.006em; }
.srch-rest span { display: block; font-size: 11px; color: var(--ink-2); margin-top: 1px; }
.gbp { border: 1px solid var(--line); border-radius: 6px; padding: 12px 12px 11px; }
.gbp-n { font-size: 14px; color: var(--ink); margin: 0 0 5px; letter-spacing: -.008em; }
.gbp-m { font-size: 11.5px; color: var(--ink-2); margin: 0 0 3px; display: flex; align-items: center; gap: 6px; }
.gbp-m b { font-weight: 500; color: var(--ink); }
.gbp-m em { font-style: normal; color: #1a7f4b; }
.stars { color: #f0a028; letter-spacing: .5px; font-size: 11px; }
.gbp-post { font-size: 12px; line-height: 1.45; color: var(--ink); margin: 9px 0 0;
  padding: 8px 9px; background: rgba(11,114,168,.06); border-radius: 4px; }
.gbp-btns { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.gbp-btns span { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--accent);
  border: 1px solid rgba(11,114,168,.3); border-radius: 999px; padding: 4px 9px; }

/* local search: the query is the point, so the card starts with the search bar */
.srch { display: flex; flex-direction: column; gap: 10px; }
.srch-bar { display: flex; align-items: center; gap: 7px; margin: 0;
  border: 1px solid var(--line); border-radius: 999px; padding: 8px 12px;
  font-size: 12px; color: var(--ink-2); background: rgba(10,10,10,.02); }
.srch-bar svg { width: 12px; height: 12px; flex: none; fill: none; stroke: var(--ink-3);
  stroke-width: 2; stroke-linecap: round; }

/* AI answers: reads as an assistant window, not a quote block, because the
   channel is unfamiliar enough that the format has to do the explaining */
.chat { border: 1px solid var(--line); border-radius: 8px; padding: 11px 11px 10px;
  background: rgba(10,10,10,.015); display: flex; flex-direction: column; gap: 9px; }
.chat-you { align-self: flex-end; max-width: 92%; margin: 0; font-size: 12px; line-height: 1.4;
  background: rgba(10,10,10,.06); color: var(--ink); padding: 8px 10px;
  border-radius: 10px; border-bottom-right-radius: 3px; }
.chat-ai { background: #fff; border: 1px solid var(--line); border-radius: 10px;
  border-bottom-left-radius: 3px; padding: 10px 11px; }
.chat-who { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 6px;
  display: flex; align-items: center; gap: 5px; }
.chat-who i { font-style: normal; font-size: 11px; line-height: 1; }
.chat-t { font-size: 12.5px; line-height: 1.5; color: var(--ink); margin: 0; }
.chat-t b { font-weight: 500; }
.chat-s { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9px; letter-spacing: .05em;
  color: var(--ink-3); margin: 8px 0 0; display: flex; align-items: center; gap: 5px; }
.chat-s i { width: 8px; height: 8px; border-radius: 2px; background: var(--accent-lt); display: block; }
.chat-in { margin: 2px 0 0; border: 1px solid var(--line); border-radius: 999px; background: #fff;
  padding: 7px 11px; font-size: 11.5px; color: var(--ink-3);
  display: flex; align-items: center; justify-content: space-between; }
.chat-in span { width: 15px; height: 15px; border-radius: 50%; background: var(--accent); flex: none; }

/* reviews: the rating widget is what everyone recognises, so show it being used */
.rate { border: 1px solid rgba(11,114,168,.3); border-radius: 6px; padding: 10px 11px; text-align: center; }
.rate-l { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3); margin: 0 0 7px; }
.rate-s { margin: 0 0 9px; display: flex; justify-content: center; gap: 4px; }
.rate-s b { color: #f0a028; font-size: 17px; line-height: 1; font-weight: 400; }
.rate-btn { margin: 0; font-size: 11.5px; color: #fff; background: var(--accent);
  border-radius: 4px; padding: 6px 10px; }

/* rebooking: a client record, not another text thread. The section right after
   this one is a text thread, and two of them read as the same picture twice. */
.rec { border: 1px solid var(--line); border-radius: 6px; padding: 11px 12px 12px; }
.rec-n { font-size: 13px; color: var(--ink); margin: 0 0 11px; display: flex;
  align-items: baseline; gap: 7px; }
.rec-n em { font-style: normal; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.rec-t { list-style: none; margin: 0; padding: 0 0 0 15px; position: relative; }
.rec-t::before { content: ''; position: absolute; left: 3px; top: 5px; bottom: 5px;
  width: 1px; background: var(--line); }
.rec-t li { position: relative; font-size: 12px; line-height: 1.4; color: var(--ink-2);
  padding: 0 0 11px; display: flex; flex-direction: column; gap: 1px; }
.rec-t li:last-child { padding-bottom: 0; }
.rec-t li::before { content: ''; position: absolute; left: -15px; top: 4px; width: 7px; height: 7px;
  border-radius: 50%; background: #fff; border: 1.5px solid var(--ink-3); }
.rec-t li.now::before { background: var(--accent); border-color: var(--accent); }
.rec-t b { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9.5px; letter-spacing: .06em;
  color: var(--ink-3); font-weight: 400; }
.rec-t li.now { color: var(--ink); }

/* reviews and rebooking both run as short threads */
.thr { display: flex; flex-direction: column; gap: 6px; }
.thr .b { font-size: 12px; line-height: 1.45; margin: 0; padding: 8px 10px; border-radius: 10px; max-width: 92%; }
.thr .out { background: var(--accent); color: #fff; align-self: flex-start; border-bottom-left-radius: 3px; }
.thr .in  { background: rgba(10,10,10,.055); color: var(--ink); align-self: flex-end; border-bottom-right-radius: 3px; }
.thr-tag { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9.5px; letter-spacing: .05em;
  color: var(--ink-3); margin: 11px 0 0; }
.rev { border: 1px solid var(--line); border-radius: 6px; padding: 10px 11px; }
.rev-s { margin: 0 0 5px; display: flex; align-items: center; gap: 8px; }
.rev-s em { font-style: normal; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); }
.rev-t { font-size: 12px; line-height: 1.45; color: var(--ink-2); margin: 0; }

@media (max-width: 1000px) { .chn { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } }
@media (max-width: 620px)  { .chn { grid-template-columns: 1fr; gap: 14px; } }

/* ── proof, pricing, faq, footer ──────────────────── */
.proof { display: grid; grid-template-columns: 1.05fr .95fr; gap: 64px; align-items: center; }
.proof .quote { font-size: clamp(22px, 2.3vw, 30px); line-height: 1.32; letter-spacing: -.018em; margin: 0; }
.proof .who { margin-top: 22px; }
.proof .d3 { height: 26px; width: auto; opacity: .8; display: block; margin-bottom: 12px; }

/* plans left, what-you-get right. Two cards alone used 780px of a 1232px
   measure and left the rest of the page blank. */
.pricewrap { display: grid; grid-template-columns: minmax(0,1.05fr) minmax(0,1fr); gap: 20px 60px; align-items: start; }
.price { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.incl { padding-top: 2px; }
.inclh { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-2); font-weight: 400; margin: 0; }
.incl .feats { margin-top: 14px; }
.plan { border: 1px solid var(--line); border-radius: var(--r); padding: 30px 28px; display: flex;
  flex-direction: column; transition: border-color .18s var(--ease-out); }
.plan.best { border-color: rgba(11,114,168,.42); }
.plan .tier { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-2); display: flex; justify-content: space-between; }
.plan .tier em { font-style: normal; color: var(--accent); }
.plan .amt { font-size: 46px; letter-spacing: -.035em; margin: 16px 0 4px; }
.plan .amt small { font-size: 17px; color: var(--ink-2); letter-spacing: 0; }
.plan .billed { font-size: 14px; color: var(--ink-2); }
.plan .save { font-size: 13px; color: var(--ink-3); margin-top: 4px; }
/* the annual card carries an extra line of small print, so a fixed gap left
   the two buttons on different baselines. auto pushes both to the card floor. */
.plan .btn { margin-top: auto; }
.plan .save { margin-bottom: 26px; }
.feats { list-style: none; margin: 30px 0 0; padding: 0; }
.feats li { padding: 11px 0; border-top: 1px solid var(--line); font-size: 15px; color: var(--ink-2); }

.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary { list-style: none; cursor: pointer; padding: 22px 0; font-size: 17.5px;
  display: flex; justify-content: space-between; gap: 24px; align-items: baseline; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary i { font-style: normal; color: var(--ink-3); flex: none; font-size: 20px; line-height: 1;
  transition: transform .2s var(--ease-out); }
.faq details[open] summary i { transform: rotate(45deg); }
.faq .a { padding: 0 0 24px; max-width: 68ch; font-size: 15.5px; line-height: 1.62; color: var(--ink-2); margin: 0; }

.foot { border-top: 1px solid var(--line); padding: 62px 0 40px; }
/* brand block left, four labelled link columns right. Ten links in one flat
   row gave equal weight to Terms and to How it works. */
.footin { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1.45fr); gap: 44px 60px; align-items: start; }
.foot .brand { padding: 10px 0; margin: -10px 0; }
.ftag { font-size: 14px; line-height: 1.6; color: var(--ink-2); margin: 16px 0 0; max-width: 30ch; }
.fmail { display: inline-block; font-size: 14px; color: var(--ink-2); margin-top: 14px;
  padding: 6px 0; border-bottom: 1px solid var(--line); }
.fmail:hover { color: var(--accent); border-color: rgba(11,114,168,.5); }
.fcols { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 32px 24px; }
.flabel { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin: 0 0 4px; }
.fcol nav { display: flex; flex-direction: column; }
.fcol a { font-size: 14px; color: var(--ink-2); padding: 7px 0; width: fit-content; }
.fcol a:hover { color: var(--ink); }
.foot .cr { font-size: 13px; color: var(--ink-3); margin-top: 52px;
  border-top: 1px solid var(--line); padding-top: 24px; }

/* the closing block is the only centred section, so its parts have to be
   centred explicitly. .lede and .micro are both left-aligned by default. */
.cta-end .lede { margin: 20px auto 0; text-align: center; max-width: 54ch; }
.cta-end .micro { justify-content: center; margin-top: 26px; }

/* set by the menu script; position:fixed is the only body lock iOS honours */
body.navlock { position: fixed; left: 0; right: 0; width: 100%; overflow: hidden; }

/* ── skip link, for keyboard users landing on a long page ── */
.skip { position: absolute; left: -9999px; top: 0; z-index: 100; background: var(--ink); color: #fff;
  padding: 12px 20px; border-radius: 0 0 var(--r) 0; font-size: 14px; }
.skip:focus { left: 0; }

/* ── page header + breadcrumbs, for the inner pages ── */
.phead { padding: 62px 0 46px; border-bottom: 1px solid var(--line); }
.crumbs { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10.5px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3); margin: 0 0 22px; }
.crumbs a { border-bottom: 1px solid transparent; transition: border-color .16s var(--ease-out);
  /* the link box was 15px tall. pad it out to a real target without moving
     the text, so the crumb line keeps its position. */
  display: inline-block; padding: 10px 2px; margin: -10px -2px; }
.crumbs a:hover { border-color: var(--ink-3); }
.phead h1 { font-size: clamp(32px, 4vw, 56px); }
.phead .lede { margin-top: 20px; }

/* ── about: the founders ── */
.founders { display: grid; grid-template-columns: 1fr 1fr; gap: 26px; }
/* the two bios are different lengths, so the LinkedIn links sat on different
   baselines. Stretch the text column; the link is floored in its own rule. */
.founder > div:last-child { display: flex; flex-direction: column; }
.founder { display: grid; grid-template-columns: 190px 1fr; gap: 26px; align-items: stretch;
  border: 1px solid var(--line); border-radius: var(--r); padding: 24px; }
.founder .pic { width: 190px; aspect-ratio: 4/5; border-radius: var(--r); overflow: hidden;
  background: var(--paper-2); position: relative; }
.founder .pic img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Om's source is a full-body graduation portrait, Rahul's is a head-and-shoulders
   headshot. The live site's scale(1.34) leaves Om tiny next to Rahul, so crop to
   his face (roughly 53% across, 36% down) hard enough that the two cards match. */
.founder .pic.om img { transform: scale(2.7); transform-origin: 53% 36%; }
.founder h3 { font-size: 20px; font-weight: 500; letter-spacing: -.02em; margin: 0; }
.founder .role { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent); margin: 6px 0 0; }
.founder .bio { font-size: 14.5px; line-height: 1.62; color: var(--ink-2); margin: 14px 0 0; }
/* the box was 21px tall. The underline is a border-bottom, so it can only grow
   upward without detaching from the text; the margin gives back what the
   padding takes so the link does not move. */
.founder .li { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  margin-top: auto; padding-top: 14px;
  font-size: 13.5px; border-bottom: 1px solid var(--line); padding-bottom: 2px;
  transition: color .16s var(--ease-out), border-color .16s var(--ease-out); }
.founder .li:hover { color: var(--accent); border-color: rgba(11,114,168,.5); }

.vision { border: 1px solid var(--line); border-radius: var(--r); padding: 32px 30px; }
.vision img { width: 34px; display: block; margin-bottom: 20px; }
.vision h2 { font-size: 24px; font-weight: 400; letter-spacing: -.02em; line-height: 1.28; margin: 0; }
.vision p { font-size: 15.5px; line-height: 1.62; color: var(--ink-2); margin: 16px 0 0; }
.vision ul { list-style: none; margin: 22px 0 0; padding: 0; }
.vision li { padding: 11px 0; border-top: 1px solid var(--line); font-size: 15px; }

/* ── contact ── */
.contact { display: grid; grid-template-columns: 1fr 1fr; gap: 26px; }
.ccard { border: 1px solid var(--line); border-radius: var(--r); padding: 30px 28px; }
.ccard h2 { font-size: 21px; font-weight: 400; letter-spacing: -.02em; margin: 0; }
.ccard p { font-size: 15px; line-height: 1.6; color: var(--ink-2); margin: 12px 0 22px; }

/* ── a fact table, which is what answer engines actually quote ── */
.facts { width: 100%; max-width: 940px; border-collapse: collapse; margin-top: 30px; }
.facts th, .facts td { text-align: left; padding: 14px 0; border-bottom: 1px solid var(--line);
  font-size: 15px; font-weight: 400; vertical-align: top; }
.facts th { width: 34%; color: var(--ink-2); font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase; padding-right: 24px; }

.notfound { padding: 130px 0 140px; text-align: center; }

.ph-note { display: flex; align-items: center; justify-content: center; text-align: center;
  background: rgba(10,10,10,.04); border: 1px dashed rgba(10,10,10,.2); border-radius: var(--r);
  font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); padding: 20px; }

/* ── responsive ───────────────────────────────────── */
@media (max-width: 1000px) {
  :root { --pad: 20px; }
  .sec { padding: 58px 0; } .sec-tight { padding: 44px 0; }
  /* Brand left, burger right, links in a panel. The old wrapped second row
     fit, but it read as a leftover rather than a decision. */
  .navin { height: 64px; }
  /* the lockup is a link home; it was an 18px target once the old mobile
     nav block that used to pad it went away */
  .navin > .brand { padding: 13px 0; margin: -13px 0; }
  .burger { display: inline-flex; }
  .navmenu {
    display: flex; flex-direction: column; position: fixed;
    left: 0; right: 0; top: 64px; bottom: 0; z-index: 59;
    background: var(--paper);
    padding: 12px var(--pad) calc(30px + env(safe-area-inset-bottom, 0px));
    overflow-y: auto; overscroll-behavior: contain;
    opacity: 0; visibility: hidden; transform: translateY(-8px);
    transition: opacity .2s var(--ease-out), transform .28s var(--ease-out),
                visibility 0s linear .28s; }
  .nav.open .navmenu { opacity: 1; visibility: visible; transform: none;
    transition: opacity .2s var(--ease-out), transform .28s var(--ease-out), visibility 0s; }
  .navmenu .nl { flex-direction: column; gap: 0; font-size: 18px; color: var(--ink); }
  .navmenu .nl a { padding: 17px 2px; border-bottom: 1px solid var(--line); }
  .navmenu .nl a::after { display: none; }
  .navmenu .nl a[aria-current="page"] { color: var(--accent); }
  .navmenu .btn-sm { width: 100%; margin-top: 28px; font-size: 15px; padding: 16px 24px; }
  /* the panel is full-height, so without this the space under the button
     reads as the menu having been cut off rather than finished */
  .navfoot { margin: auto 0 0; padding-top: 32px; display: flex; justify-content: space-between;
    font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11.5px;
    letter-spacing: .045em; color: var(--ink-3); }
  .navfoot a { color: var(--ink-2); padding: 6px 0; margin: -6px 0; }
  .footin { grid-template-columns: 1fr; gap: 38px; }
  .fcols { grid-template-columns: 1fr 1fr; gap: 28px 20px; }
  /* the secondary CTA drops under the button on mobile. block, not
     inline-block, or it sits back up on the button's line; width:fit-content
     so the 12px padding does not make the whole row clickable. */
  .alt { display: block; width: fit-content; margin: 8px 0 0; padding: 12px 0; }
  .trip { grid-template-columns: 1fr; }
  .proof, .price { grid-template-columns: 1fr; gap: 32px; }
  .pricewrap { grid-template-columns: 1fr; gap: 40px; }
  .morph .stage { height: 420px; }
  .alloc .row { grid-template-columns: 70px 1fr 62px; gap: 10px; }
  .nevers b { width: 66px; }
  .founders, .contact { grid-template-columns: 1fr; }
  .founder { grid-template-columns: 108px 1fr; gap: 16px; padding: 16px; }
  .founder .pic { width: 108px; }
  .phead { padding: 38px 0 32px; }
  /* two columns inside 350px left every answer in a 210px gutter, five lines
     deep. Stacked, the label sits above its value at full measure. */
  .facts, .facts tbody, .facts tr, .facts th, .facts td { display: block; width: auto; }
  .facts tr { border-bottom: 1px solid var(--line); padding: 12px 0 14px; }
  .facts th { width: auto; padding: 0 0 5px; border: 0; }
  .facts td { padding: 0; border: 0; }
  .notfound { padding: 80px 0 90px; }
}

@media (max-width: 560px) {
  /* Put all four surfaces within thumb reach before the preview. The old
     wrapped row orphaned Facebook and left every target below 44px. */
  .morph .chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    width: 100%; gap: 8px; margin: 0 0 24px; }
  .morph .chip { min-height: 44px; padding: 10px 12px; }
  /* Use the full content width for square creative while keeping every
     format inside one stable stage as its aspect ratio changes. */
  .morph .stage { height: min(360px, calc(100vw - 40px)); }
  .morph .ratio { min-height: 2.8em; max-width: 30ch; margin-top: 16px; }
}

/* ── reduced motion: nothing moves, everything is visible ── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .r, .ph { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  .clock .step, .clock .step::before { opacity: 1 !important; transform: none !important; }
  .clock .spine i { transform: scaleY(1) !important; }
  .alloc .fill { transform: scaleX(var(--to)) !important; }
  .field .cloud, .mx-wash .cloud { animation: none !important; }
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* ══════════════════════════════════════════════════════════════
   Social post chrome.
   The campaign images were reading as loose graphics. Wrapping them
   in the actual furniture of a feed post (profile row, caption,
   engagement row) is what makes them read as posts
   that ran, rather than art we made.

   Each post carries its own business identity, because the claim of
   this section is that the creative is tailored per business. One
   shared look would argue the opposite.
   ══════════════════════════════════════════════════════════════ */
.post { background: #fff; border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
  display: flex; flex-direction: column; }
.onfield .post { border-color: rgba(255,255,255,.16); }

/* the fictional brands carry longer names than the placeholders did, and the
   name row was ellipsising. Reclaimed the width from padding, gap and avatar
   rather than shrinking the name into illegibility. */
.post .phead { display: flex; align-items: center; gap: 8px; padding: 11px 10px; }
.post .avatar { width: 28px; height: 28px; border-radius: 999px; flex: none; display: grid;
  place-items: center; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 12px;
  font-weight: 500; color: #fff; letter-spacing: .02em; }
.post .who { min-width: 0; flex: 1; }
.post .name { display: block; font-size: 12px; font-weight: 500; color: var(--ink); letter-spacing: -.006em;
  line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.post .meta { display: block; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); line-height: 1.3; margin-top: 2px; }
.post .dots { flex: none; color: var(--ink-3); font-size: 15px; line-height: 1; letter-spacing: .06em; }
/* the four-up grid gives the header ~71px for a name. The overflow menu is
   pure chrome, so it yields first rather than the business name. */
.ads .post .dots { display: none; }

/* The old art had a burned-in "YOUR MED SPA" slot at the top, so the window was
   pulled down to 96% to hide it, and a chip was laid over the corner. The new
   creatives are finished posts whose own logo sits exactly there, so both
   workarounds damaged the thing they were protecting.
   The box matches the artwork's real 1003x1568 ratio. It is not 4:5: the
   supplied webp files had been squashed into 4:5 from a 1003x1568 master,
   which widened every face by about a quarter. Rebuilt from the masters at
   their own aspect, so nothing is squashed and nothing is cropped. */
.post .media { position: relative; aspect-ratio: 1003 / 1568; overflow: hidden; background: var(--paper-2); }
.post .media img { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }

.post .acts { display: flex; align-items: center; gap: 13px; padding: 9px 12px 0; color: var(--ink-2); }
.post .acts svg { width: 17px; height: 17px; display: block; }
.post .acts .spacer { flex: 1; }
.post .cap { padding: 7px 12px 13px; font-size: 12px; line-height: 1.45; color: var(--ink-2); margin: 0; }
.post .cap b { font-weight: 500; color: var(--ink); }
.post .cta { margin: 0 12px 12px; padding: 8px 10px; border-radius: 4px; text-align: center;
  font-size: 12px; font-weight: 500; color: #fff; }
/* a light brand colour cannot carry white text: butter yellow runs 1.44:1
   against white and 12:1 against ink */
.post .cta-dark { color: #1a1a1a; }

/* ── brand sheet: what "your brand kit" actually means ── */
.kit { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin-top: 22px; }
.kit > div { background: var(--paper); padding: 18px 16px 20px; }
.kit .lbl { display: block; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 12px; }
.kit .wordmark { font-size: 17px; letter-spacing: .16em; font-weight: 500; }
.kit .sub { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin-top: 5px; }
.kit .swatches { display: flex; gap: 6px; }
.kit .swatches i { width: 26px; height: 26px; border-radius: 3px; display: block;
  box-shadow: inset 0 0 0 1px rgba(10,10,10,.08); }
.kit .spec { font-size: 20px; letter-spacing: -.02em; line-height: 1.1; }
.kit .spec em { font-style: normal; color: var(--ink-3); }
.kit .rules { font-size: 12px; line-height: 1.5; color: var(--ink-2); margin: 0; }
@media (max-width: 900px) { .kit { grid-template-columns: 1fr 1fr; } }
@media (max-width: 480px) { .kit { grid-template-columns: 1fr; } }

/* ── the follow-up, as it actually looks ──
   A timeline of labels told you a reply happened. Showing the messages
   tells you what the customer received, which is the part an owner is
   actually deciding about. Labelled as an example, not a real thread. */
.thread { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 14px 14px 16px; }
.thread .th { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: 11px; margin-bottom: 13px; border-bottom: 1px solid var(--line); }
.thread .th b { font-size: 12.5px; font-weight: 500; color: var(--ink); }
.thread .th span { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); }
.thread .sys { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); text-align: center;
  margin: 0 0 12px; }
.thread .msg { max-width: 84%; padding: 9px 12px; border-radius: 14px; font-size: 13px;
  line-height: 1.45; margin: 0 0 8px; }
.thread .msg.out { background: var(--paper-2); color: var(--ink); border-bottom-left-radius: 4px; }
.thread .msg.in { background: var(--accent); color: #fff; margin-left: auto;
  border-bottom-right-radius: 4px; }
.thread .stamp2 { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .07em; color: var(--ink-3); margin: -4px 0 12px; }
.thread .stamp2.r { text-align: right; }
.thread .done { display: flex; align-items: center; gap: 8px; margin-top: 13px; padding-top: 12px;
  border-top: 1px solid var(--line); font-size: 12.5px; color: var(--ink); }
.thread .done s { width: 15px; height: 15px; border-radius: 999px; background: var(--accent);
  flex: none; display: grid; place-items: center; color: #fff; font-size: 9px; text-decoration: none; }

/* ── one slot, two proofs ──
   The thread and the notification stack together ran the column past a full
   screen, and they answer different questions, so they now share the slot as
   tabs, the same interaction the morph already taught this page. Without JS
   the chips stay hidden and both panels show stacked, which is just the old
   layout. Chip state changes atomically, no colour transition: same lesson as
   the morph chips, a label easing across a filling background spends real
   frames unreadable. */
.vt-chips { display: none; gap: 8px; margin-bottom: 14px; }
.vt-chips.on { display: flex; }
.vt-chips .chip { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .07em; text-transform: uppercase; padding: 9px 15px; border-radius: 999px;
  cursor: pointer; background: transparent; color: rgba(255,255,255,.65);
  border: 1px solid rgba(255,255,255,.28); }
.vt-chips .chip[aria-selected="true"] { background: #fff; color: var(--ink); border-color: #fff; }
.vt-chips .chip:active { transform: scale(0.97); }
.vt-panel[hidden] { display: none; }
.vt-panel .route-cap { margin-top: 0; }

/* ── the routing proof: the phone itself ──
   A lone "routed to you" notification begged the question of why you need it
   when Instagram already buzzed. The answer is the stack: the DMs and texts an
   owner's phone collects all evening are here, each one marked answered,
   because the agent handled them without anyone looking. The one card at full
   contrast is the only one that needed a person, and it arrives as a briefing,
   not an alert: who, what, and the whole chat attached. Dim rows ellipsize on
   one line, they are texture; the hot row wraps, it is the payload. */
.route-cap { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px;
  letter-spacing: .07em; text-transform: uppercase; color: rgba(255,255,255,.78);
  text-align: center; margin: 22px 0 12px; }
.ntfs { display: flex; flex-direction: column; gap: 7px; }
.ntf { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 12px;
  background: rgba(255,255,255,.13); color: #fff; }
/* real app glyphs, drawn inline so nothing external loads. The agent row
   carries Velora's own circled-V monogram, same mark as its campaign cards. */
.ntf .nico { width: 26px; height: 26px; flex: none; display: block; }
.ntf .nt { min-width: 0; flex: 1; }
.ntf b { display: block; font-size: 11.5px; font-weight: 500; }
.ntf span { display: block; font-size: 12px; color: rgba(255,255,255,.72);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the action labels are the argument: what got handled, and how. Answered
   rows carry a green check, the drafted reply waits in amber with its approve
   nudge, and the routed card keeps the brand cyan. Colour does the sorting
   before anyone reads a word. */
.ntf em { font-style: normal; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 9.5px;
  font-weight: 500; letter-spacing: .06em; text-transform: uppercase; flex: none; text-align: right; }
.ntf em.ok { color: #8df0a8; display: flex; align-items: center; gap: 4px; }
.ntf em.ok s { text-decoration: none; font-size: 10.5px; line-height: 1; }
.ntf em.draft { color: #ffd76a; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.ntf em.draft i { font-style: normal; font-size: 8.5px; font-weight: 400; letter-spacing: .05em;
  color: rgba(255,255,255,.55); }
.ntf.hot { align-items: flex-start; background: rgba(15,17,21,.94); padding: 11px 12px;
  box-shadow: 0 10px 26px rgba(0,0,0,.3); }
.ntf.hot b { font-size: 12.5px; margin-bottom: 2px; }
.ntf.hot span { white-space: normal; color: rgba(255,255,255,.85); line-height: 1.4; }
.ntf.hot em { color: #7fd0f5; margin-top: 2px; }

/* ── proof: this is the strongest thing on the page, size it that way ── */
.bigproof { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin-top: 34px; }
.bigproof .bpin { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line); }
.bigproof .cell { background: var(--paper); padding: 26px 22px 28px; }
.bigproof .cell span { display: block; font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 9px; }
.bigproof .cell b { font-size: clamp(26px, 3.4vw, 40px); font-weight: 400; letter-spacing: -.03em;
  line-height: 1; display: block; }
.bigproof .cell b.hi { color: var(--accent); }
.bigproof .src { background: var(--paper-2); padding: 13px 22px; display: flex; flex-wrap: wrap;
  gap: 6px 22px; align-items: center; font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: .05em; color: var(--ink-2); }
.bigproof .src img { height: 15px; width: auto; opacity: .8; }
@media (max-width: 900px) { .bigproof .bpin { grid-template-columns: 1fr 1fr; } }
@media (max-width: 460px) { .bigproof .bpin { grid-template-columns: 1fr; } }

/* ── the spine: six channels, one page, one number ──
   The site described an ads tool. The actual product is that every channel
   lands on a page Osmoti built, which is the only reason the number at the
   end can be trusted. That claim needed somewhere to live. */
.chans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin: 40px 0 0; }
.chans article { background: var(--paper); padding: 24px 22px 26px; }
.chans .tag { display: block; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 11px; }
.chans h3 { font-size: 15px; font-weight: 500; letter-spacing: -.01em; margin: 0 0 7px; }
.chans p { font-size: 14px; line-height: 1.56; color: var(--ink-2); margin: 0; }
.funnel { margin: 26px 0 0; display: grid; grid-template-columns: 1fr auto 1fr auto 1fr; gap: 14px;
  align-items: center; }
.funnel .node { border: 1px solid var(--line); border-radius: var(--r); padding: 16px 18px; background: var(--paper); }
.funnel .node b { display: block; font-size: 14.5px; font-weight: 500; margin-bottom: 4px; }
.funnel .node span { font-size: 13px; line-height: 1.5; color: var(--ink-2); }
.funnel .arw { font-family: 'Geist Mono', ui-monospace, monospace; color: var(--ink-3); font-size: 15px; }
.funnel .node.own { border-color: rgba(11,114,168,.4); }
.funnel .node.own b { color: var(--accent); }
@media (max-width: 1000px) { .chans { grid-template-columns: 1fr 1fr; }
  .funnel { grid-template-columns: 1fr; } .funnel .arw { display: none; } }
@media (max-width: 560px) { .chans { grid-template-columns: 1fr; } }

/* ── comparison table ──
   The format AI systems quote most often, so it is built as a real table
   with a header row rather than styled divs. */
.vs { width: 100%; max-width: 940px; border-collapse: collapse; margin-top: 30px; font-size: 15px; }
.vs th, .vs td { text-align: left; padding: 14px 18px 14px 0; border-bottom: 1px solid var(--line);
  vertical-align: top; line-height: 1.5; }
.vs thead th { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); font-weight: 400; border-bottom-color: var(--ink); }
.vs tbody th { font-weight: 400; color: var(--ink); width: 27%; }
.vs td { color: var(--ink-2); }
.vs .yes { color: var(--accent); }
.vs tr.tot th, .vs tr.tot td { border-bottom: 0; padding-top: 18px; color: var(--ink); }
.vs tr.tot td b { font-weight: 400; color: var(--accent); }
@media (max-width: 760px) {
  .vs, .vs tbody, .vs tr, .vs th, .vs td { display: block; width: auto; }
  .vs thead { display: none; }
  .vs tr { border-bottom: 1px solid var(--line); padding: 4px 0 12px; }
  /* .vs tbody th (0,1,2) outranks the .vs th reset above (0,1,1), so the 27%
     column width survived into the stacked layout and wrapped every label
     into two or three lines inside a 94px box. */
  .vs tbody th { padding: 12px 0 2px; border: 0; width: auto; }
  .vs td { padding: 0 0 4px; border: 0; }
  .vs td::before { content: attr(data-l) " · "; font-family: 'Geist Mono', ui-monospace, monospace;
    font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
}

/* two derived figures, shown as arithmetic rather than as more headline tiles */
.mathrow { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 20px; margin-top: 28px; max-width: 720px; }
.mathcell { border: 1px solid var(--line); border-radius: var(--r); padding: 22px 24px; }
.mathcell span { display: block; font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .09em; text-transform: uppercase; color: var(--ink-2); }
.mathcell b { display: block; font-size: 34px; font-weight: 400; letter-spacing: -.03em; margin: 10px 0 6px; }
.mathcell em { font-style: normal; font-size: 13px; color: var(--ink-3); }

/* the limits list. Deliberately not styled as a warning: it is part of the
   argument, not a disclaimer bolted to the end of it. */
.limits { list-style: none; margin: 26px 0 0; padding: 0; max-width: 74ch; }
.limits li { padding: 15px 0; border-top: 1px solid var(--line); font-size: 15.5px;
  line-height: 1.62; color: var(--ink-2); }
.limits li b { font-weight: 400; color: var(--ink); }
@media (max-width: 700px) { .mathrow { grid-template-columns: 1fr; gap: 14px; } }

/* Who it is for. Named .whogrid, not .who: the social-post header already owns
   .who, and an unscoped .who put a grey bordered grid behind every post card
   on the homepage.
   A single paragraph listing fifteen industries is a wall of
   nouns nobody reads. Grouped, a visitor finds their own row in about a
   second, and it stays shorter than the paragraph it replaced. */
.whogrid { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; margin-top: 34px; }
.whocard { background: var(--paper); padding: 20px 22px; }
.wholabel { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 10px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--accent); margin: 0; }
.wholist { font-size: 15.5px; line-height: 1.5; color: var(--ink); margin: 12px 0 0; }
@media (max-width: 1000px) { .whogrid { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 620px)  { .whogrid { grid-template-columns: 1fr; } }

/* ── direct-answer block: the paragraph an AI system lifts ── */
.answer { border-left: 2px solid var(--accent); padding: 2px 0 2px 18px; margin: 26px 0 0;
  font-size: 18px; line-height: 1.55; letter-spacing: -.012em; color: var(--ink); max-width: 60ch; }
