/* ============================================================
   kaitlian — one day, and the work floats on it in glass.

   Tokens come from the product (design.ts / globals.css), so the
   site and the app speak one language.

   Pebble-horizon palette:
     Deep Harbor  #12344F   primary, the mark's circle, text
     Marina Blue  #5CA9C8   water, accents
     Sand         #E6CFAD   the sun dot, kept rare
     Shell        #F7F4EC   reversed text on dark
     Warm Shell   #F7F3EE   paper

   The homepage is a single day: a real sea under a single-scattering
   sky, both keyed to the visitor's own clock (app.js), with every
   section a surface floating on it and open water between them. The
   chrome (nav, footer) is the same glass at lower opacity. Blocks
   with no surface under them solve their ink against the scene.
   ============================================================ */

@font-face{
  font-family:'Hanken Grotesk';
  src:url('/fonts/hanken-grotesk-latin.woff2') format('woff2');
  /* The full axis, as the product declares it. Understating the range lets
     WebKit mis-select the variation instance and drop glyphs on iOS. */
  font-weight:100 900; font-display:swap; font-style:normal;
}

:root{
  /* brand constants */
  --marina:#5CA9C8;
  --sand:#E6CFAD;

  /* warm shell paper */
  color-scheme:light;
  --bone:#F7F3EE;
  --bone-lift:#FDFAF6;
  --bone-sink:#F0EBE3;
  --hover:#FFFFFF;

  --ink:#12344F;
  --ink-2:#2E4A63;
  --ink-soft:#51636F;
  --ink-faint:#6B6152;   /* warm grey, solved to clear 4.5:1 on the darkest card ground */

  --sea:#2E6B8A;
  --sea-deep:#245571;
  --sea-wash:#E7F0F5;

  --hair:rgba(18,52,79,.14);
  --hair-strong:rgba(18,52,79,.26);
  --hair-ink:rgba(18,52,79,.10);
  --mark-circle:#12344F;

  /* Where the light is. The driver writes these every minute; the fallbacks
     are one plausible afternoon, for the static page. */
  --sun-dx:0px; --sun-dy:34px; --sun-cast:.5;

  --e-1:0 1px 2px rgba(18,52,79,.05), 0 2px 8px -4px rgba(18,52,79,.08);
  --e-2:0 2px 4px rgba(18,52,79,.05), 0 12px 28px -14px rgba(18,52,79,.22);
  --e-3:0 4px 10px rgba(18,52,79,.06), 0 30px 60px -30px rgba(18,52,79,.34);

  --r-sm:10px; --r:14px; --r-lg:20px; --r-xl:26px; --r-pill:999px;
  --r-panel:clamp(18px,2.2vw,34px);
  --sans:'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --ease:cubic-bezier(.22,.61,.36,1);
  --dur-1:.12s; --dur-2:.24s;

  --gutter:clamp(20px, 5vw, 56px);
  --maxw:1200px;
  --tap:48px;
}

*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; scroll-padding-top:88px; }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }
/* The washes behind on-scene type are inset well past their own boxes, which on
   a phone reaches past the viewport and makes the whole document sixty pixels
   wider than the screen. That is felt as the page sliding sideways under a
   thumb that was only trying to scroll. Clip, not hidden: hidden would make the
   root a scroll container and change how the fixed chrome behaves. */
html{ overflow-x:clip; }
body{ overflow-x:clip; }

body{
  margin:0; background:var(--bone); color:var(--ink-soft);
  font-family:var(--sans); font-size:17px; line-height:1.6; font-weight:400;
  letter-spacing:.002em;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  overflow-x:clip; min-height:100vh;
}

/* Headings are the product's voice: semibold sans, tight tracking, no serif. */
h1,h2,h3,h4{
  font-family:var(--sans); color:var(--ink); font-weight:600; margin:0;
  line-height:1.08; letter-spacing:-.022em; text-wrap:balance;
}
h1{ font-size:clamp(2.6rem, 6.2vw, 5rem); letter-spacing:-.032em; line-height:1.02; }
h2{ font-size:clamp(2rem, 4.2vw, 3.2rem); letter-spacing:-.028em; }
h3{ font-size:1.2rem; letter-spacing:-.014em; line-height:1.3; }
p{ margin:0; text-wrap:pretty; }
strong,b{ font-weight:600; color:var(--ink); }

a{ color:var(--sea); text-underline-offset:3px; text-decoration-thickness:1px;
   transition:color var(--dur-1) var(--ease); }
@media (hover:hover){ a:where(:not(.btn)):hover{ color:var(--sea-deep); } }

:where(a,button,input,textarea,select,[tabindex],summary):focus-visible{
  outline:2.5px solid var(--sea); outline-offset:3px; border-radius:8px;
  box-shadow:0 0 0 5px var(--sea-wash);
}

.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gutter); }
.skip{ position:absolute; left:-9999px; top:0; background:var(--ink); color:var(--bone);
  padding:10px 16px; border-radius:8px; z-index:200; }
.skip:focus{ left:16px; top:12px; }

/* ---- the mark ---- */
.mark{ display:block; flex:none; }
.lantern{ position:relative; display:grid; place-items:center; flex:none; }

/* ---- buttons (product .btn grammar) ---- */
.btn{ -webkit-appearance:none; appearance:none; display:inline-flex; align-items:center;
  justify-content:center; gap:.5em; font-family:var(--sans); font-size:16px; font-weight:600;
  letter-spacing:-.005em; min-height:var(--tap); padding:13px 24px; border-radius:var(--r);
  border:1px solid transparent; text-decoration:none; cursor:pointer; white-space:nowrap;
  background:transparent; color:var(--ink);
  transition:transform var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease),
    background var(--dur-2) var(--ease), border-color var(--dur-1) var(--ease); }
.btn svg{ width:16px; height:16px; transition:transform var(--dur-2) var(--ease); }
.btn-primary{ background:var(--ink); color:var(--bone); box-shadow:var(--e-2); }
.btn-soft{ background:var(--bone-lift); color:var(--ink); border-color:var(--hair); box-shadow:var(--e-1); }
@media (hover:hover){
  .btn-primary:hover{ transform:translateY(-1px); box-shadow:var(--e-3); }
  .btn-primary:hover svg{ transform:translateX(3px); }
  .btn-soft:hover{ border-color:var(--hair-strong); background:var(--hover); }
}
/* The press must read on touch too, where there is no hover lift to cancel:
   a real scale-down, on a faster clock than the hover polish. */
.btn:active{ transition-duration:160ms; }
.btn-primary:active,.btn-soft:active{ transform:translateY(0) scale(.97); box-shadow:var(--e-2); }
.btn-go:active,.nav .btn-nav:active{ transition-duration:160ms; }

.kicker{ font-size:12px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--sea); display:inline-flex; align-items:center; gap:.7em; }

/* ---- lenis ---- */
html.lenis, html.lenis body{ height:auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped{ overflow:clip; }
.lenis [data-lenis-prevent],
.lenis [data-lenis-prevent-wheel],
.lenis [data-lenis-prevent-touch],
.lenis [data-lenis-prevent-vertical],
.lenis [data-lenis-prevent-horizontal]{ overscroll-behavior:contain; }
.lenis.lenis-smooth iframe{ pointer-events:none; }
.lenis.lenis-autoToggle{ transition-property:overflow; transition-duration:1ms;
  transition-behavior:allow-discrete; }

/* ============================================================
   THE HOMEPAGE
   ============================================================ */

.home{ background:#0B141B; }

/* ============ THE SKY ============ */
/* The WebGL shader draws the real sky (app.js). The CSS gradient stack under it
   is the fallback for three cases: no WebGL2 context, a lost context, and the
   static daylight page that reduced-motion and no-JS visitors get. */
/* The sky overshoots the viewport on both ends so iOS bar-collapse and
   rubber-band overscroll reveal MORE SKY, never the flat body colour behind
   it (which can only match one edge). lvh keeps the overshoot stable while
   Safari's bars come and go; browsers without lvh drop the custom properties
   and the var() fallbacks put the edges back at 0, exactly the old layout. */
:root{ --sky-ot:clamp(80px,12lvh,180px); --sky-ob:clamp(120px,22lvh,300px); }
.sky{ position:fixed; inset:0; z-index:-1; pointer-events:none; overflow:hidden;
  top:calc(-1 * var(--sky-ot,0px)); bottom:calc(-1 * var(--sky-ob,0px)); }
.sky .layer{ position:absolute; inset:0; will-change:opacity; }

/* The static daylight sky: what a visitor with no renderer, no JS, or reduced
   motion gets. One honest hour, with a horizon painted in so the hero's
   composition still reads. */
.sky.static .l-astro,.sky.static .l-nautical,.sky.static .l-civil,.sky.static .l-day{ opacity:1; }
.sky.static .stars{ opacity:0; }
.sky.static .sun{ opacity:1; transform:translate3d(0,-6vh,0) scale(1.04); }
.sky.static::after{ content:""; position:absolute; left:0; right:0;
  top:calc(var(--sky-ot,0px) + 64lvh); bottom:0;
  background:linear-gradient(180deg,
    #C9D9E1 0%, #9FBCCC 3%, #7FA6BC 26%, #5E8CA6 62%, #4E7C96 100%); }

/* deep night: always painted, everything else fades in over it */
.l-night{ background:
  radial-gradient(120% 62% at 50% 116%, rgba(92,169,200,.16), transparent 62%),
  linear-gradient(180deg, #080F15 0%, #0B141B 38%, #101C25 72%, #14222D 100%); }
.l-astro{ opacity:0; background:
  radial-gradient(110% 55% at 50% 112%, rgba(92,169,200,.30), transparent 60%),
  linear-gradient(180deg, #0A121A 0%, #102030 44%, #16304A 78%, #1B3A58 100%); }
.l-nautical{ opacity:0; background:
  radial-gradient(95% 48% at 50% 106%, rgba(230,207,173,.34), transparent 58%),
  linear-gradient(180deg, #12243A 0%, #1D4062 40%, #2E6083 72%, #4A7E9B 100%); }
.l-civil{ opacity:0; background:
  radial-gradient(85% 44% at 50% 102%, rgba(245,214,170,.62), transparent 56%),
  linear-gradient(180deg, #2C5A80 0%, #5A8AA6 34%, #9DAFB2 62%, #D8C3A4 86%, #EBD8BC 100%); }
.l-day{ opacity:0; background:
  linear-gradient(180deg, #DCE6EC 0%, #EDEAE4 42%, #F7F3EE 78%, #F7F3EE 100%); }

.stars{ position:absolute; inset:0 0 42% 0; will-change:opacity; }
.stars i{ position:absolute; width:2px; height:2px; border-radius:50%; background:#F7F4EC; }

/* The fallback sun: a body of light, never a hard disc. It rises on the right,
   where the sand dot sits in the mark. */
/* Anchored back to the VIEWPORT's bottom: the element it sits in now extends
   past the viewport, and 16% of the taller box would sink the sun. */
.sun{ position:absolute; left:70%; bottom:16%; bottom:calc(var(--sky-ob,0px) + 16lvh); width:clamp(300px,38vw,560px); aspect-ratio:1;
  margin-left:calc(clamp(300px,38vw,560px) / -2);
  will-change:transform,opacity; transform:translate3d(0,44vh,0) scale(.82); opacity:0;
  background:radial-gradient(circle at 50% 50%,
    #FFF6E6 0%, #F3DFBE 22%, #E6CFAD 36%, rgba(230,207,173,.46) 52%,
    rgba(230,207,173,.18) 68%, rgba(230,207,173,0) 82%); }

/* Hidden until the context is live, so a failed init shows the gradients
   rather than a black rectangle. */
.sky-gl{ position:absolute; inset:0; width:100%; height:100%; display:none; }
.sky-gl.on{ display:block; }
/* When the harbor renders, it IS the sky: the WebGL2 sky beneath it and the
   gradient stack beneath that both stand down.

   It also drops the overshoot. The gradient stack extends past the viewport so
   iOS overscroll reveals more sky instead of flat body colour, but the harbor
   has a horizon in it, measured as a fraction of the canvas: a canvas taller
   than the viewport puts that horizon somewhere the layout did not ask for,
   and makes the top-of-sky sample the page paints its chrome with come from a
   row nobody can see. The body background tracks the real top of the scene
   instead, so overscroll reveals exactly the colour it is pulling away from. */
/* Anchored to the top and sized to the LARGE viewport, so iOS bar-collapse
   grows the page into a canvas that is already there instead of revealing a
   strip of body colour under the toolbar. Browsers without lvh fall back to
   vh, which is the same thing wherever there is no collapsing bar. */
.sky.harbor{ top:0; bottom:auto; height:100vh; height:100lvh; }
/* Phones: the scene is the opening, not the ground. app.js measures where the
   paper starts and sizes it to match, so the two meet on a crisp edge. */
@media (max-width:680px){
  .sky{ position:absolute; }
  .sky.harbor{ height:var(--scene-h, 100lvh); }
}
.sky.harbor .layer,.sky.harbor .stars,.sky.harbor .sun{ display:none; }
.sky.gl .layer,.sky.gl .stars{ display:none; }

/* Phones once opened on a flat field so Safari's status area had one stable
   colour to sample. Against a real horizon that field IS the seam: a hard
   horizontal band across the sky, worse than the problem it solved. The body
   background tracks the top of the rendered scene now (app.js), on phones as
   on desktop, so there is one colour and it is the right one. */

/* ---- the cap ----
   Phones get one flat field under the status area, and the scene begins below
   it. This is not the browser's colour tracking the sky; it is the page giving
   the browser one honest colour to sit on.

   The band is the SAME colour as the top of the rendered scene (app.js writes
   --chrome from the probe), so where it meets the sky there is nothing to see,
   and it fades out over most of the first screen so the divergence further down
   never arrives as an edge. Solid where the status bar is, gone by the time the
   headline starts.

   The earlier version of this was a hardcoded 270px slab of #B9CDD8, which
   banded against every hour that was not late morning. The colour has to come
   from the scene and the fade has to be long, or the cure is the disease. */
.sky-cap{ display:none; }
@media (max-width:680px){
  .sky-cap{ display:block; position:absolute; left:0; right:0; top:0;
    height:46vh; pointer-events:none;
    background:linear-gradient(180deg,
      var(--chrome,#B9CDD8) 0,
      var(--chrome,#B9CDD8) calc(env(safe-area-inset-top,0px) + 34px),
      color-mix(in srgb, var(--chrome,#B9CDD8) 82%, transparent) calc(env(safe-area-inset-top,0px) + 104px),
      color-mix(in srgb, var(--chrome,#B9CDD8) 38%, transparent) 58%,
      transparent 100%); }
}

/* grain: what turns a smooth gradient into light */
.grain{ position:fixed; inset:0; z-index:-1; pointer-events:none; opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }

/* ============ CHROME ============ */
/* The chip collapses to the mark once the opening is behind you (nav.js).
   The wordmark is clipped rather than removed: a chip that changes width by
   swapping its contents pops, and one that closes over its own text reads as
   the same object getting out of the way. Opening the menu expands it again. */
.nav .brand .wm{ display:inline-block; overflow:hidden; white-space:nowrap;
  max-width:8ch; transition:max-width .26s var(--ease), opacity .18s var(--ease); }
.nav .brand .chev{ overflow:hidden; max-width:14px;
  transition:max-width .26s var(--ease), opacity .18s var(--ease),
             margin-left .26s var(--ease), transform var(--dur-2) var(--ease); }
.nav .brand{ transition:gap .26s var(--ease), padding .26s var(--ease); }
/* Collapsing has to take the GAPS with it. Three flex children with a 10px gap
   leave 20px of empty track behind when two of them close to zero width, and
   the mark ends up sitting left of centre in its own button, which is exactly
   as obvious as it sounds. Equal padding then makes it a square. */
.navshell.compact:not(.open) .brand{ gap:0; padding-inline:10px; }
.navshell.compact:not(.open) .brand .wm,
.navshell.compact:not(.open) .brand .chev{ max-width:0; opacity:0; margin-left:0; }

/* Two floating pieces, not a bar: the mark on the left, the actions on the
   right, sky running between them. The glass is the panel's material at lower
   opacity, with deep ink, legible over any hour's sky. */
.navshell{ position:fixed; top:clamp(10px,1.4vh,18px); left:0; right:0; z-index:90;
  padding-inline:clamp(14px,4.5vw,76px); pointer-events:none; }
.navshell .wrap{ position:relative; max-width:1140px; margin-inline:auto; padding:0;
  pointer-events:auto; }

/* An absolutely-positioned pseudo paints ABOVE plain inline content, so the
   children are lifted. Not isolation:isolate — that would cut backdrop-filter
   off from the sky it samples. */
.gpane{ position:relative; border-radius:clamp(14px,1.5vw,20px); }
.gpane > *{ position:relative; z-index:1; }
.gpane::before{ content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  background:rgba(247,243,238,.62);
  border:1px solid rgba(18,52,79,.10);
  box-shadow:0 2px 6px rgba(18,52,79,.06), 0 18px 40px -22px rgba(18,52,79,.28);
  -webkit-backdrop-filter:blur(20px) saturate(150%); backdrop-filter:blur(20px) saturate(150%); }

/* stretch, not center: a wordmark and a 40px button size differently, and
   centring leaves the two pieces at different heights side by side. */
.nav{ position:relative; display:flex; align-items:stretch; justify-content:space-between;
  gap:20px; color:#12344F; }
.navgroup{ display:flex; align-items:center; gap:10px; padding:7px 8px 7px 14px; }
.brand{ display:flex; align-items:center; gap:10px; text-decoration:none; color:inherit; }
.nav .brand{ padding:9px 18px; }
.brand .wm{ font-size:19px; font-weight:600; letter-spacing:-.028em; }
.navlinks{ display:flex; align-items:center; gap:2px; }
/* No opacity on the links: fading ink toward its ground is what costs contrast.
   Weight carries the hierarchy instead. */
.navlink{ font-size:14px; font-weight:500; color:inherit; text-decoration:none;
  padding:9px 14px; border-radius:10px; transition:background var(--dur-1); }
@media (hover:hover){ .navlink:hover{ background:color-mix(in oklab, currentColor 10%, transparent); } }
.nav .btn-nav{ display:inline-flex; align-items:center; min-height:40px; padding:9px 20px;
  font-size:14.5px; font-weight:600; border-radius:12px; text-decoration:none; white-space:nowrap;
  background:#12344F; color:#F7F3EE;
  transition:transform var(--dur-2) var(--ease), background var(--dur-2) var(--ease); }
@media (hover:hover){ .nav .btn-nav:hover{ background:#1B4767; transform:translateY(-1px); } }
.nav .btn-nav:active{ transform:scale(.975); }
.navtoggle{ display:none; width:40px; height:40px; align-items:center; justify-content:center;
  background:transparent; border:1px solid color-mix(in oklab, currentColor 26%, transparent);
  border-radius:12px; color:inherit; opacity:.85; cursor:pointer; }

/* At night, while the nav floats over pure sky, the glass goes dark: smoked
   glass with Shell ink, part of the night instead of a light sticker on it.
   The moment the hero card reaches the nav, or the sky brightens, the light
   glass returns. JS drives .night from the same top-of-sky colour the body
   background tracks; without JS (and on the static reduced-motion page,
   which is daylight) the nav simply stays light. */
/* Background and border crossfade; the shadow snaps. Its delta between the
   two states is invisible at 400ms, and shadow animation is paint, not GPU. */
.navshell .gpane::before{ transition:background .4s var(--ease), border-color .4s var(--ease); }
.nav{ transition:color .4s var(--ease); }
.navshell.night .gpane::before{
  background:rgba(11,20,27,.46);
  border:1px solid rgba(247,244,236,.16);
  box-shadow:0 2px 6px rgba(0,0,0,.18), 0 18px 40px -22px rgba(0,0,0,.5); }
.navshell.night .nav{ color:#F7F4EC; }
.navshell.night .btn-nav{ background:#F7F3EE; color:#12344F; }
@media (hover:hover){ .navshell.night .btn-nav:hover{ background:#FFFFFF; } }

/* One object in the chrome: the brand chip. Clicking it pours the menu out
   of the chip — same glass, same radius family — and clicking again pours it
   back. The overshoot curve is what makes it read as liquid. */
/* On the homepage the chrome is one centred object: everything visible on
   the page is centred, so the chip centres too. The subpages keep their
   left brand + right links row. */
.home .nav, .paper .nav{ justify-content:center; }
.home .nav .brand{ padding:10px 20px; }
.home .brand .wm{ font-size:20px; }
.home .brand .mark{ width:32px; height:32px; }
.nav button.brand{ appearance:none; background:none; border:0; font:inherit;
  color:inherit; cursor:pointer; padding:10px 20px;
  transition:transform 160ms cubic-bezier(.23,1,.32,1); }
.nav button.brand .wm{ font-size:20px; }
.nav button.brand .mark{ width:32px; height:32px; }
.nav button.brand:active{ transform:scale(.97); }
.brand .chev{ margin-left:1px; opacity:.55;
  transition:transform 200ms cubic-bezier(.23,1,.32,1); }
.navshell.open .brand .chev{ transform:rotate(180deg); }

/* Enter gets a whisper of overshoot at 230ms; exit is plain strong ease-out
   and faster, because the system's answer should be snappier than the ask.
   Everything rides transform and opacity only. */
.navflyout{ position:absolute; top:calc(100% + 10px); left:50%; min-width:322px;
  display:grid; grid-template-columns:1fr 1fr; gap:2px; padding:10px;
  opacity:0; pointer-events:none; will-change:transform,opacity;
  transform:translate(-50%,-4px);
  transition:transform 140ms cubic-bezier(.23,1,.32,1), opacity 110ms cubic-bezier(.23,1,.32,1); }
.navshell.open .navflyout{ opacity:1; pointer-events:auto; transform:translate(-50%,0);
  transition:transform 200ms cubic-bezier(.23,1,.32,1), opacity 150ms cubic-bezier(.23,1,.32,1); }
/* The chip can be live glass because it never moves. The flyout moves, and a
   backdrop-filter surface re-samples everything behind it on every animated
   frame, which shimmers. So the sheet is solid: no blur, no scale, just a
   crisp drop. It was 93% opaque anyway; readability over card text wanted
   this too. */
.navflyout::before{ background:#F5F1EA; -webkit-backdrop-filter:none; backdrop-filter:none; }
.navshell.night .navflyout::before{ background:#101C26; }

.navflyout a{ position:relative; z-index:1; font-size:15px; font-weight:500;
  color:inherit; text-decoration:none; padding:11px 14px; border-radius:10px;
  opacity:0; transform:translateY(-5px);
  transition:opacity 120ms cubic-bezier(.23,1,.32,1),
             transform 150ms cubic-bezier(.23,1,.32,1), background var(--dur-1); }
.navflyout a:active{ transform:scale(.98); transition-duration:160ms; }
.navflyout .fl-link[aria-current="page"]{ background:var(--sea-wash); font-weight:600; }
.navshell.night .navflyout .fl-link[aria-current="page"]{ color:#12344F; }
.navshell.open .navflyout a{ opacity:1; transform:none;
  transition:opacity 180ms cubic-bezier(.23,1,.32,1),
             transform 220ms cubic-bezier(.23,1,.32,1), background var(--dur-1); }
.navshell.open .navflyout a:nth-child(2){ transition-delay:.018s; }
.navshell.open .navflyout a:nth-child(3){ transition-delay:.036s; }
.navshell.open .navflyout a:nth-child(4){ transition-delay:.054s; }
.navshell.open .navflyout a:nth-child(5){ transition-delay:.072s; }
.navshell.open .navflyout a:nth-child(6){ transition-delay:.09s; }
.navshell.open .navflyout a:nth-child(7){ transition-delay:.108s; }
@media (hover:hover){ .navflyout .fl-link:hover{ background:color-mix(in oklab, currentColor 10%, transparent); } }
.navflyout .fl-join{ grid-column:1 / -1; margin-top:8px; display:flex;
  align-items:center; justify-content:space-between; gap:10px; font-weight:600;
  background:#12344F; color:#F7F3EE; border-radius:12px; padding:12px 14px; }
@media (hover:hover){ .navflyout .fl-join:hover{ background:#1B4767; } }
.navshell.night .navflyout .fl-join{ background:#F7F3EE; color:#12344F; }
@media (prefers-reduced-motion: reduce){
  .navflyout, .navflyout a, .brand .chev{ transition:none !important; }
}

/* Mobile keeps the same floating nav object as desktop. */
@media (max-width:680px){
  html{ scroll-padding-top:82px; }
  body.home{ background:#B9CDD8; }
  .home main{ position:relative; z-index:1; }
  /* A fixed control at the top edge makes Safari 26 create a persistent
     scroll-edge shelf around the status area. On phones the chip belongs to
     the opening scene and scrolls away with it, leaving Safari's edge-to-edge
     treatment unobstructed. */
  .navshell{ position:absolute; top:10px; padding-inline:14px; background:transparent; }
  .navshell .wrap{ width:100%; max-width:none; }
  .home .nav,.paper .nav{ justify-content:center; }
  .nav button.brand{ width:auto; min-height:52px; padding:8px 16px;
    justify-content:center; border-radius:17px; }
  .nav button.brand .wm{ font-size:18px; }
  .nav button.brand .mark{ width:29px; height:29px; }
  .nav button.brand .chev{ margin-left:3px; }

  .navflyout{ top:calc(100% + 9px); left:50%; width:min(340px,calc(100vw - 28px)); min-width:0;
    padding:10px; border-radius:20px; transform:translate(-50%,-4px); }
  .navshell.open .navflyout{ transform:translate(-50%,0); }
  .navflyout::before,.navshell.night .navflyout::before{
    background:#F5F1EA; border-radius:20px;
    border:1px solid rgba(18,52,79,.10); box-shadow:0 22px 42px -30px rgba(18,52,79,.5); }
  /* The pane above is forced light at every hour on a phone, so the ink in it
     has to be too. Without this the links inherit the night nav's Shell and go
     invisible on their own cream: legible only because the current page happens
     to sit on a tinted chip. */
  .navshell.night .navflyout{ color:#12344F; }
  .navshell.night .navflyout .fl-join{ background:#12344F; color:#F7F3EE; }
}

/* The small-screen menu: its own near-opaque pane, one predictable ground.
   (Still used by the subpages' simpler nav.) */
.navmenu{ display:none; }
@media (max-width:680px){
  .navshell.open .navmenu{ display:flex; flex-direction:column; gap:2px;
    position:absolute; top:calc(100% + 10px); right:0; min-width:220px; padding:10px;
    border-radius:16px; background:rgba(247,243,238,.94); color:#12344F;
    border:1px solid rgba(18,52,79,.10); z-index:2;
    box-shadow:0 2px 6px rgba(18,52,79,.08), 0 24px 50px -20px rgba(18,52,79,.35);
    -webkit-backdrop-filter:blur(20px) saturate(150%); backdrop-filter:blur(20px) saturate(150%); }
  .navmenu .navlink{ padding:12px 14px; font-size:15px; color:#12344F; }
}


/* ============ THE PANEL — the page's one surface ============ */
/* Light near-opaque glass, floating centred with sky visible around it, legible
   at midnight and at noon. Crisp edges on purpose: they are what make surfaces
   read as objects floating on the sky. Only lines INSIDE a surface soften. */
.panel{ max-width:1140px; margin-inline:auto;
  margin-block:clamp(56px,12vh,140px);
  background:color-mix(in oklab, var(--bone) 92%, transparent);
  border:1px solid var(--hair); border-radius:var(--r-panel);
  box-shadow:var(--e-3);
  -webkit-backdrop-filter:blur(8px) saturate(120%); backdrop-filter:blur(8px) saturate(120%); }
.panel.pad{ padding-block:clamp(48px,7vh,88px); }

.home main{ padding-inline:clamp(14px, 4.5vw, 76px); }
.hero .wrap{ max-width:1240px; }
.join .wrap{ max-width:1140px; }

/* ============ HERO ============ */
/* No card. The headline stands on the harbor itself, and its ink is solved
   against the light actually behind it (app.js reads the rendered scene), so
   the type is legible at every hour without the page ever laying a slab over
   the thing it is asking the visitor to look at. */
/* The block is held ABOVE the horizon on purpose. Sky is a broad, slow
   gradient and type solves against it cleanly; water is a field of specular
   highlights and will fight any ink at all. Everything that must be read as
   words lives up here, and everything below the horizon arrives on a surface
   of its own. */
.hero{ position:relative; min-height:100svh; display:flex; align-items:center;
  padding-top:clamp(108px,15vh,168px); padding-bottom:clamp(120px,27vh,300px); }
.hero .wrap{ width:100%; }
.hero-copy{ max-width:min(78ch,80vw); }

.hero h1{ font-size:clamp(2.85rem,7.1vw,6.5rem); letter-spacing:-.045em;
  line-height:.93; font-weight:600; }
.hero h1 .ln{ display:block; }
/* Agency scale carries the sea accent, leaving the creator's taste in the core ink. */
.hero h1 .bw{ color:var(--sky-accent,var(--sea)); }

.hero-cta{ display:flex; flex-wrap:wrap; gap:12px; margin-top:clamp(28px,3.4vw,44px); }
.hero-fine{ margin-top:20px; font-size:13.5px; font-weight:500; }

.hero-lead{ max-width:44ch; margin-top:clamp(22px,2.6vw,32px);
  font-size:clamp(1.08rem,1.55vw,1.3rem); line-height:1.55; letter-spacing:-.01em; }
/* Five capabilities, standing on the water in their own band. Hairlines are
   drawn from the solved ink, so they fade with it rather than sitting on the
   scene as a fixed grey. */
/* ---- the destinations ----
   A current, not a bar. The version that came out of this page was a dark
   glass panel with a counter on it, which is the costume a "trusted by" logo
   marquee wears, and it repeated what the plaque below it already said. This
   one has no panel at all: the names drift on the water in the hero's open
   band, in the ink the scene solves for them, at a speed slow enough to belong
   to the sea rather than compete with it.

   Its wash is a wide horizontal haze rather than the usual ellipse, because a
   full-width strip backed by an ellipse reads as an object and the whole point
   is that this is not one. */
/* The current lives inside the hero now, directly under the fine print, so it
   reads as the last line of the pitch rather than a separate band drifting near
   the horizon. */
/* Draggable and nothing else. It used to be a link to Connections, but with no
   bar, no border and no arrow there is nothing about a row of names on water
   that says "tap me", so navigating on tap was a surprise every time. That
   route lives in the nav, the footer and the plaque's own list. */
.destinations{ display:block; color:inherit; margin-top:clamp(26px,3.2vh,40px);
  cursor:grab; -webkit-user-select:none; user-select:none;
  -webkit-tap-highlight-color:transparent; }
.destinations.is-dragging{ cursor:grabbing; }
/* No wash behind this one at all. A band the width of the screen reads as a bar
   whatever its opacity, and because the wash takes the OPPOSITE colour to the
   solved ink, it flipped from pale to dark as the day crossed the ink's flip
   point: a shadow that came and went while somebody was only scrolling. The
   halo does this block's work instead, and a halo hugs the glyphs rather than
   drawing a shape of its own. */
.destinations::before{ display:none; }
/* touch-action:pan-y is the whole of why this works under a thumb. It tells the
   browser that vertical panning belongs to the page and horizontal belongs
   here, so a drag and a scroll stop guessing about each other. Without it a JS
   drag on touch fights the page every frame and feels broken, which is what
   happened when this was rebuilt without it. */
/* A little vertical padding INSIDE the link: the row of names is 24px, which
   is an unfair thing to ask a thumb to hit. This pads the target toward 42
   without moving the type, and the surrounding water still belongs to the
   water. */
.dest-window{ overflow:hidden; position:relative; touch-action:pan-y;
  padding-block:9px; -webkit-user-select:none; user-select:none;
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
  mask-image:linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%); }
.dest-track{ display:flex; width:max-content; will-change:transform; }
.dest-set{ display:flex; align-items:center; gap:clamp(26px,3.4vw,46px);
  padding-inline:clamp(13px,1.7vw,23px); }
.dest-item{ display:inline-flex; align-items:center; gap:9px; white-space:nowrap;
  font-size:14px; font-weight:600; letter-spacing:-.005em; }
@media (max-width:680px){
  .dest-item{ font-size:15px; }
  .dest-item svg{ width:20px; height:20px; }
}
.dest-item svg{ width:19px; height:19px; flex:none; fill:none; stroke:currentColor;
  stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round; opacity:.82; }
@media (prefers-reduced-motion: reduce){
  .dest-window{ overflow-x:auto; scrollbar-width:none; }
  .dest-window::-webkit-scrollbar{ display:none; }
  .dest-track{ will-change:auto; }
  .dest-set[aria-hidden="true"]{ display:none; }
}

/* Five capabilities on one low plaque, floating on the water. A pane rather
   than solved ink: this is the first place the page states what the staff
   actually does, and the water underneath is a field of moving highlights that
   no ink survives. */
/* The plaque inherits the ride the destinations used to take up into the
   hero's tail: the hero is a full viewport with its copy held above the
   horizon, and without this pull the plaque starts below the fold. */
.capabilities{ margin-top:calc(-1 * clamp(96px,21vh,232px)); padding-bottom:clamp(18px,3vh,34px); }
/* Five cells need more width than the text column gives. The plaque runs
   wider than .wrap so each cell keeps a readable measure. */
.capabilities .wrap{ max-width:1400px; }
.hero-capabilities{ display:grid; grid-template-columns:repeat(5,minmax(0,1fr));
  gap:0; margin:0; padding:0; list-style:none;
  /* No overflow:hidden here. The cells paint no background of their own, so
     the pane's own radius already rounds it, and clipping would swallow the
     platform popover that opens out of the first cell. */
  border-radius:clamp(16px,1.8vw,24px);
  background:color-mix(in oklab, var(--bone-lift) 90%, transparent);
  border:1px solid rgba(18,52,79,.13);
  box-shadow:calc(var(--sun-dx) * .7) var(--sun-dy) 78px -50px rgba(6,18,28,var(--sun-cast)),
             0 2px 8px -4px rgba(6,18,28,.16);
  -webkit-backdrop-filter:blur(16px) saturate(128%); backdrop-filter:blur(16px) saturate(128%); }
/* Each cell is a claim and its one line of proof. No bullets: a bulleted
   paragraph on a plaque reads as a spec sheet, and the heading already does
   the pointing. The body drops to the second ink so the four claims read
   first, as a row, before any of the sentences do. */
/* Sized to be read from a laptop without leaning in: the body sits just under
   the hero lead, the claim just over it. */
.hero-capabilities li{ position:relative; padding:clamp(24px,2.4vw,32px) clamp(18px,1.7vw,24px);
  color:var(--ink-2); font-size:clamp(15.5px,1.15vw,17px); font-weight:450; line-height:1.5; letter-spacing:-.004em; }
.hero-capabilities li b{ display:block; margin-bottom:8px; color:var(--ink);
  font-size:clamp(17px,1.3vw,19.5px); font-weight:650; letter-spacing:-.018em; line-height:1.25; }
.hero-capabilities li{ border-radius:inherit; }
.hero-capabilities li + li{ box-shadow:inset 1px 0 0 var(--hair-ink); }
.platform-symbols{ position:absolute; width:0; height:0; overflow:hidden; }
.platform-tail{ white-space:nowrap; }
.platform-hover{ position:relative; display:inline-block; vertical-align:baseline; }
.platform-trigger{ appearance:none; display:inline-grid; margin:-2px -3px; padding:2px 3px;
  border:0; border-radius:6px; background:transparent; color:var(--sea-deep); cursor:pointer;
  font:inherit; font-weight:inherit; line-height:inherit; letter-spacing:inherit;
  transition:background-color 160ms ease, color 160ms ease; }
.platform-rotator{ display:inline-grid; justify-items:start; white-space:nowrap; vertical-align:baseline;
  overflow:hidden; padding-bottom:.14em; margin-bottom:-.14em; color:var(--sea-deep); }
.platform-word{ grid-area:1/1; display:inline-block;
  transform:translate3d(0,135%,0); transition:transform .42s cubic-bezier(.68,-.02,.22,1.03); }
.platform-word.is-in{ transform:translate3d(0,0,0); }
.platform-word.is-out{ transform:translate3d(0,-135%,0); }
.platform-word svg{ width:1em; height:1em; margin-right:.32em; vertical-align:-.12em;
  fill:none; stroke:currentColor; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round; }
.platform-popover{ --popover-x:-30%; --notch-x:30%; --popover-bg:color-mix(in oklab,var(--bone-lift) 96%,transparent);
  position:absolute; z-index:20; left:50%; bottom:calc(100% + 12px); width:min(520px,calc(100vw - 56px));
  padding:13px; border:1px solid var(--hair-strong); border-radius:16px; background:var(--popover-bg);
  box-shadow:var(--e-3); white-space:normal; opacity:0; visibility:hidden; pointer-events:none;
  transform:translate3d(var(--popover-x),8px,0) scale(.97); transform-origin:var(--notch-x) 100%;
  transition:opacity 180ms ease, transform 180ms cubic-bezier(.23,1,.32,1), visibility 0s linear 180ms;
  -webkit-backdrop-filter:blur(14px) saturate(125%); backdrop-filter:blur(14px) saturate(125%); }
.platform-popover::before{ content:""; position:absolute; left:0; right:0; bottom:-14px; height:14px; }
.platform-popover::after{ content:""; position:absolute; left:var(--notch-x); bottom:-6px; width:11px; height:11px;
  border-right:1px solid var(--hair-strong); border-bottom:1px solid var(--hair-strong);
  background:var(--popover-bg); transform:translateX(-50%) rotate(45deg); }
.platform-popover-head{ display:flex; align-items:center; justify-content:space-between; gap:20px;
  padding:1px 4px 10px; border-bottom:1px solid var(--hair-ink); }
.platform-popover-head b{ color:var(--ink); font-size:12.5px; line-height:1; }
.platform-popover-head > span{ color:var(--ink-faint); font-size:10px; font-weight:650;
  line-height:1; letter-spacing:.1em; text-transform:uppercase; }
.platform-popover-close{ display:none; appearance:none; width:30px; height:30px; padding:0; border:0;
  border-radius:9px; background:var(--sea-wash); color:var(--ink); cursor:pointer; place-items:center;
  transition:transform 140ms cubic-bezier(.23,1,.32,1), background-color 140ms ease; }
.platform-popover-close:active{ transform:scale(.94); }
.platform-popover-close svg{ width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:1.8;
  stroke-linecap:round; }
.platform-popover-grid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:4px; padding-top:9px; }
/* The route to Connections used to live on a marquee under the plaque. It
   belongs here instead: at the bottom of the list of destinations, where
   someone counting them is already asking the question it answers. */
.platform-popover-more{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  margin-top:9px; padding:11px 12px; border-radius:12px; text-decoration:none;
  background:color-mix(in oklab,var(--sea) 8%,transparent);
  color:var(--sea-deep); font-size:13px; font-weight:600;
  transition:background-color var(--dur-1) var(--ease); }
.platform-popover-more svg{ width:17px; height:17px; flex:none; fill:none;
  stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
  transition:transform var(--dur-2) var(--ease); }
@media (hover:hover){
  .platform-popover-more:hover{ background:color-mix(in oklab,var(--sea) 15%,transparent); }
  .platform-popover-more:hover svg{ transform:translateX(3px); }
}
.platform-popover-item{ display:flex; align-items:center; gap:7px; min-width:0; padding:7px 6px;
  border-radius:8px; color:var(--ink-2); font-size:11.5px; font-weight:600; line-height:1.1; white-space:nowrap; }
.platform-popover-item svg{ width:17px; height:17px; flex:none; fill:none; stroke:var(--sea-deep);
  stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round; }
.platform-hover[data-open="true"] .platform-popover{ opacity:1; visibility:visible; pointer-events:auto;
  transform:translate3d(var(--popover-x),0,0) scale(1); transition-delay:0s; }
.platform-popover[data-open="true"]{ opacity:1; visibility:visible; pointer-events:auto;
  transform:translate3d(var(--popover-x),0,0) scale(1); transition-delay:0s; }
@media (hover:hover) and (pointer:fine){
  .platform-trigger:hover{ background:color-mix(in oklab,var(--sea-wash) 72%,transparent); color:var(--ink); }
  .platform-hover:hover .platform-popover{ opacity:1; visibility:visible; pointer-events:auto;
    transform:translate3d(var(--popover-x),0,0) scale(1); transition-delay:0s; }
}
@media (hover:hover) and (pointer:fine){
}
.hero-cta{ margin-top:30px; display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.hero-fine{ max-width:38rem; margin-top:18px; font-size:14px; line-height:1.5; color:var(--ink-faint); }

/* ============ THE PRODUCT — one large scene, not another feature deck ============ */
.product-proof{ position:relative; margin-block:clamp(72px,12vh,190px); padding-block:clamp(76px,10vh,128px);
  background:color-mix(in oklab, var(--bone) 94%, transparent); border:1px solid var(--hair);
  border-radius:var(--r-panel); box-shadow:var(--e-3);
  -webkit-backdrop-filter:blur(8px) saturate(120%); backdrop-filter:blur(8px) saturate(120%); }
.product-proof .wrap{ max-width:1380px; }
.proof-head{ max-width:54rem; margin-inline:auto; text-align:center; }
.proof-head .kicker{ justify-content:center; }
.proof-head h2{ margin-top:16px; font-size:clamp(2.7rem,6vw,5.45rem); letter-spacing:-.052em;
  line-height:.96; }
.proof-head p{ max-width:47rem; margin:24px auto 0; color:var(--ink-2);
  font-size:clamp(1.05rem,1.6vw,1.25rem); line-height:1.58; }

.workplace{ margin-top:clamp(48px,6vw,76px); overflow:hidden;
  background:var(--bone-lift); border:1px solid rgba(18,52,79,.18); border-radius:clamp(20px,2.4vw,34px);
  box-shadow:0 38px 90px -48px rgba(10,33,51,.58), 0 4px 16px rgba(18,52,79,.08); }
.workplace-bar{ min-height:58px; display:grid; grid-template-columns:1fr auto 1fr; align-items:center;
  padding:0 20px; border-bottom:1px solid var(--hair-ink); background:#F8F4ED; }
.workplace-brand{ display:flex; align-items:center; gap:8px; color:var(--ink); font-size:14px; font-weight:650; }
.workplace-project{ color:var(--ink-2); font-size:13px; font-weight:600; display:flex; align-items:center; gap:8px; }
.project-dot{ width:7px; height:7px; border-radius:50%; background:var(--sand); box-shadow:0 0 0 4px rgba(230,207,173,.25); }
.workplace-live{ justify-self:end; display:flex; align-items:center; gap:7px; color:var(--ink-soft);
  font-size:11px; font-weight:650; letter-spacing:.08em; text-transform:uppercase; }
.workplace-live > span{ width:7px; height:7px; border-radius:50%; background:#4B9B76; box-shadow:0 0 0 4px rgba(75,155,118,.13); }

.workplace-body{ display:grid; grid-template-columns:148px minmax(290px,.76fr) minmax(520px,1.54fr);
  min-height:620px; }
.workplace-nav{ padding:22px 12px; background:#F4EFE7; border-right:1px solid var(--hair-ink); }
.workplace-nav-label{ display:block; padding:0 10px 13px; color:var(--ink-faint); font-size:9.5px;
  font-weight:700; letter-spacing:.12em; text-transform:uppercase; }
.workplace-nav-item{ height:37px; padding:0 10px; border-radius:10px; display:flex; align-items:center; gap:9px;
  color:var(--ink-soft); font-size:12px; font-weight:550; }
.workplace-nav-item i{ width:15px; color:var(--ink-2); font-style:normal; text-align:center; font-size:13px; }
.workplace-nav-item.active{ background:#DDEBF2; color:var(--ink); font-weight:650; }

.workplace-chat{ min-width:0; background:#FCF9F5; border-right:1px solid var(--hair-ink); }
.chat-person{ height:67px; display:flex; align-items:center; gap:10px; padding:0 17px; border-bottom:1px solid var(--hair-ink); }
.agent-avatar{ width:32px; height:32px; border-radius:50%; display:grid; place-items:center; flex:none;
  color:#F8F4ED; background:var(--ink); border:2px solid var(--sand); font-size:12px; font-weight:700; }
.agent-avatar.small{ width:25px; height:25px; border:0; font-size:10px; }
.agent-avatar.coral{ background:#C97F6F; border-color:#F4DED6; }
.agent-avatar.blue{ background:#477B9B; border-color:#DCEAF2; }
.chat-person > span:nth-child(2),.staff-runs > div > span:nth-child(2){ min-width:0; display:grid; }
.chat-person b{ color:var(--ink); font-size:13px; }
.chat-person small{ color:var(--ink-faint); font-size:10.5px; line-height:1.25; }
.chat-online{ margin-left:auto; color:#397C5D; font-size:9.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; }
.chat-scroll{ padding:22px 17px; }
.chat-label,.review-kicker{ color:var(--sea-deep); font-size:9px; font-weight:750; letter-spacing:.13em; text-transform:uppercase; }
.chat-bubble{ margin:8px 0 0 auto; width:94%; padding:14px 15px; border-radius:16px 16px 4px 16px;
  background:var(--ink); color:#F8F4ED; font-size:12px; line-height:1.48; }
.chat-reply{ display:flex; align-items:flex-start; gap:9px; margin-top:18px; }
.chat-reply p{ color:var(--ink-2); font-size:12px; line-height:1.48; }
.staff-runs{ margin-top:20px; border:1px solid var(--hair); border-radius:13px; overflow:hidden; background:#FFFDFC; }
.staff-runs > div{ min-height:54px; display:flex; align-items:center; gap:9px; padding:9px 11px; border-top:1px solid var(--hair-ink); }
.staff-runs > div:first-child{ border-top:0; }
.staff-runs .agent-avatar{ width:27px; height:27px; font-size:10px; }
.staff-runs b{ color:var(--ink); font-size:11.5px; }
.staff-runs small{ color:var(--ink-faint); font-size:9.5px; line-height:1.2; white-space:nowrap; }
.staff-runs em{ margin-left:auto; color:#397C5D; font-size:9px; font-weight:700; font-style:normal;
  letter-spacing:.09em; text-transform:uppercase; }
.review-return{ margin-top:17px; padding:15px; border-radius:13px; background:#F7EEDD; border:1px solid #EBD6B4; }
.review-return strong{ display:block; margin-top:4px; color:var(--ink); font-size:14px; }
.review-return p{ margin-top:3px; color:var(--ink-soft); font-size:10.5px; line-height:1.4; }
.review-return > div{ display:flex; gap:7px; margin-top:12px; }
.review-return > div span{ padding:7px 10px; border-radius:8px; font-size:10px; font-weight:650; }
.review-primary{ background:var(--ink); color:#F8F4ED; }
.review-secondary{ color:var(--ink); border:1px solid rgba(18,52,79,.16); background:#FFF9F0; }

.workplace-computer{ min-width:0; background:#E8E3DC; }
.computer-bar{ min-height:67px; display:flex; align-items:center; justify-content:space-between; gap:18px;
  padding:0 18px; border-bottom:1px solid rgba(18,52,79,.14); background:#F7F3EE; }
.computer-bar > div:first-child{ display:grid; }
.computer-title{ color:var(--ink); font-size:13px; font-weight:700; }
.computer-owner{ color:var(--ink-faint); font-size:10.5px; }
.computer-tabs{ display:flex; gap:3px; padding:3px; border-radius:10px; background:#EBE6DF; }
.computer-tabs span{ padding:6px 9px; border-radius:7px; color:var(--ink-faint); font-size:9.5px; font-weight:650; }
.computer-tabs .active{ background:#FFFDFC; color:var(--ink); box-shadow:0 1px 2px rgba(18,52,79,.1); }
.computer-canvas{ height:553px; display:grid; grid-template-columns:minmax(0,1fr) 174px; }
.edit-stage{ min-width:0; padding:16px; background:#202932; }
.video-frame{ position:relative; height:360px; overflow:hidden; border-radius:10px; background:
  radial-gradient(circle at 64% 38%, #F7D7AA 0 8%, transparent 8.5%),
  radial-gradient(circle at 54% 51%, #CC684B 0 10%, transparent 10.5%),
  linear-gradient(138deg,#283E46 0 38%,#8D5C45 38% 57%,#DCA16E 57% 73%,#263C41 73%); }
.video-frame::after{ content:""; position:absolute; inset:0; background:linear-gradient(180deg,rgba(7,17,23,.08),transparent 45%,rgba(7,17,23,.62)); }
.plate{ position:absolute; left:50%; top:47%; width:190px; height:120px; translate:-50% -50%; border-radius:50%;
  background:#EAE2D8; border:7px solid rgba(255,255,255,.42); box-shadow:0 22px 35px rgba(18,20,17,.32); transform:rotate(-8deg); }
.plate i{ position:absolute; width:58px; height:31px; border-radius:50%; background:#9A3D2A; box-shadow:inset -8px -6px 0 rgba(52,82,47,.45); }
.plate i:nth-child(1){ left:31px; top:26px; }.plate i:nth-child(2){ left:92px; top:44px; transform:rotate(25deg); }.plate i:nth-child(3){ left:58px; top:73px; transform:rotate(-12deg); }
.cut-version{ position:absolute; z-index:2; top:14px; left:14px; padding:6px 9px; border-radius:8px;
  color:#F7F4EC; background:rgba(8,18,25,.52); font-size:9.5px; font-weight:650; }
.video-caption{ position:absolute; z-index:2; left:50%; bottom:47px; translate:-50%; color:#fff; text-shadow:0 2px 5px rgba(0,0,0,.45);
  font-size:clamp(13px,1.3vw,18px); font-weight:700; white-space:nowrap; }
.video-controls{ position:absolute; z-index:2; left:14px; right:14px; bottom:12px; display:flex; gap:9px; align-items:center;
  color:#F7F4EC; font-size:8.5px; font-variant-numeric:tabular-nums; }
.video-controls i{ height:2px; flex:1; background:rgba(255,255,255,.42); position:relative; }
.video-controls i::before{ content:""; position:absolute; left:0; top:0; width:18%; height:100%; background:#fff; }
.timeline{ height:143px; position:relative; margin-top:14px; padding-top:19px; border-top:1px solid rgba(247,244,236,.13); }
.timeline-times{ position:absolute; left:31px; right:4px; top:0; display:flex; justify-content:space-between;
  color:rgba(247,244,236,.42); font-size:7.5px; font-variant-numeric:tabular-nums; }
.timeline-row{ display:grid; grid-template-columns:25px repeat(4,1fr); height:42px; gap:3px; margin-top:4px; }
.timeline-row b{ color:rgba(247,244,236,.48); font-size:8px; font-weight:600; align-self:center; }
.timeline-row span{ border-radius:4px; background:linear-gradient(135deg,#915C49,#E0AB73); }
.audio-track{ grid-template-columns:25px 1fr; height:29px; }
.audio-track span{ background:repeating-linear-gradient(90deg,#5CA9C8 0 2px,transparent 2px 5px),rgba(92,169,200,.18); }
.playhead{ position:absolute; z-index:3; top:13px; bottom:0; left:31%; width:1px; background:#E7C789; }
.playhead::before{ content:""; position:absolute; top:0; left:-3px; border-left:4px solid transparent; border-right:4px solid transparent; border-top:6px solid #E7C789; }
.computer-inspector{ padding:17px 13px; background:#F2EEE8; border-left:1px solid rgba(18,52,79,.12); }
.inspector-label{ color:var(--ink-faint); font-size:8px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; }
.computer-inspector > div{ display:flex; gap:8px; align-items:center; padding:13px 0; border-bottom:1px solid var(--hair-ink); }
.computer-inspector > div span{ min-width:0; display:grid; }
.computer-inspector b{ color:var(--ink); font-size:10.5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.computer-inspector small{ color:var(--ink-faint); font-size:9px; }
.file-dot{ width:24px; height:24px; border-radius:7px; flex:none; background:#D3A46E; }
.file-dot.reference{ background:#CC7969; }.file-dot.browser{ background:#6A9DB4; }
.computer-inspector p{ margin-top:20px; color:var(--ink-soft); font-size:9.5px; line-height:1.48; }

.workplace-foot{ min-height:76px; display:flex; align-items:center; justify-content:space-between; gap:28px;
  padding:15px 20px; border-top:1px solid var(--hair-ink); background:#F8F4ED; }
.workplace-foot p{ max-width:42rem; color:var(--ink-soft); font-size:12.5px; line-height:1.45; }
.workplace-foot > div{ display:flex; gap:16px; flex-wrap:wrap; justify-content:flex-end; }
.workplace-foot > div span{ color:var(--ink-faint); font-size:9.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; }
.proof-close{ max-width:48rem; margin:clamp(42px,5vw,66px) auto 0; text-align:center; color:var(--ink-2);
  font-size:clamp(1.28rem,2.3vw,1.85rem); font-weight:600; line-height:1.35; letter-spacing:-.02em; }
/* ============ SECTION CONTENT ============ */
.sec-head{ max-width:44rem; }
.sec-head h2{ margin-top:14px; }
.sec-head p{ margin-top:18px; font-size:1.12rem; line-height:1.55; color:var(--ink-soft); max-width:40rem; }

.cards{ margin-top:clamp(34px,4.2vw,54px); display:grid; grid-template-columns:repeat(12,1fr);
  gap:clamp(13px,1.5vw,18px); }
.card{ background:var(--bone-lift); border:1px solid var(--hair); border-radius:var(--r-lg);
  padding:clamp(22px,2.4vw,30px); box-shadow:var(--e-1); display:flex; flex-direction:column;
  transition:transform var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease); }
@media (hover:hover){ .card:hover{ transform:translateY(-2px); box-shadow:var(--e-2); } }
.card .cico{ width:40px; height:40px; border-radius:12px; display:grid; place-items:center;
  background:var(--sea-wash); color:var(--sea); margin-bottom:18px; }
.card .cico svg{ width:19px; height:19px; }
.card h3{ font-size:1.2rem; }
.card p{ margin-top:9px; font-size:15px; line-height:1.55; color:var(--ink-soft); }
.card.a{ grid-column:span 6; } .card.b{ grid-column:span 3; }
.cardcap{ margin-top:24px; font-size:14.5px; color:var(--ink-soft); display:flex; gap:10px; align-items:flex-start; }
.cardcap svg{ width:17px; height:17px; color:var(--sea); flex:none; margin-top:3px; }

/* the morning brief */
.morning{ margin-top:clamp(34px,4.2vw,54px); display:grid;
  grid-template-columns:minmax(0,1.02fr) minmax(0,.98fr); gap:clamp(30px,4.5vw,64px); align-items:center; }
.surface{ background:var(--bone-lift); border:1px solid var(--hair); border-radius:var(--r-xl);
  box-shadow:var(--e-3); overflow:hidden; }
.sf-top{ display:flex; align-items:center; gap:11px; padding:15px 18px; border-bottom:1px solid var(--hair-ink); }
.sf-top .lab{ font-size:11.5px; font-weight:600; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-faint); }
.sf-top .date{ margin-left:auto; font-size:11.5px; font-weight:600; letter-spacing:.08em;
  text-transform:uppercase; color:var(--ink-faint); }
.sf-greet{ padding:20px 18px 0; }
.sf-greet h3{ font-size:1.6rem; letter-spacing:-.028em; }
.sf-greet .state{ margin-top:6px; font-size:15px; color:var(--ink-soft); }
.sf-sec{ padding:18px 18px 0; }
.sf-sec-lab{ font-size:11px; font-weight:600; letter-spacing:.13em; text-transform:uppercase; color:var(--sea); }
.sf-lines{ list-style:none; margin:11px 0 0; padding:0; display:grid; gap:2px; }
.sf-lines li{ display:flex; gap:11px; align-items:flex-start; padding:9px 0; font-size:14.5px;
  line-height:1.45; color:var(--ink-2); }
.sf-lines .ico{ width:25px; height:25px; border-radius:8px; flex:none; display:grid; place-items:center;
  background:var(--sea-wash); color:var(--sea); }
.sf-lines .ico svg{ width:13px; height:13px; }
.sf-lines .when{ margin-left:auto; font-size:11.5px; color:var(--ink-faint); white-space:nowrap; padding-top:2px; }
.sf-decide{ margin:16px 18px 0; padding:13px 14px; border-radius:var(--r);
  background:color-mix(in oklab, var(--sand) 32%, var(--bone-lift));
  border:1px solid color-mix(in oklab, var(--sand) 64%, transparent);
  display:flex; align-items:center; gap:12px; }
.sf-decide .n{ width:25px; height:25px; border-radius:50%; background:var(--ink); color:var(--bone);
  display:grid; place-items:center; font-size:12.5px; font-weight:600; flex:none; }
.sf-decide .t{ font-size:14px; color:var(--ink); font-weight:500; }
.sf-decide .go{ margin-left:auto; font-size:13px; font-weight:600; color:var(--sea); }
.sf-foot{ margin-top:16px; padding:13px 18px; background:var(--bone-sink);
  border-top:1px solid var(--hair-ink); font-size:12.5px; color:var(--ink-soft); }
.surface-cap{ margin-top:13px; font-size:12.5px; color:var(--ink-faint); text-align:center; }
.morning-list{ display:grid; gap:22px; }
.ml{ padding-left:20px; border-left:2px solid var(--sea-wash); }
.ml h3{ font-size:1.1rem; }
.ml p{ margin-top:7px; font-size:15px; line-height:1.55; color:var(--ink-soft); }

/* connections */
.conn{ margin-top:clamp(34px,4vw,52px); display:grid;
  grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr); gap:clamp(30px,4.5vw,64px); align-items:center; }
.conn-chips{ display:flex; flex-wrap:wrap; gap:10px; }
.chip{ font-size:14.5px; font-weight:500; color:var(--ink-2); background:var(--bone-lift);
  border:1px solid var(--hair); border-radius:var(--r-pill); padding:9px 17px; box-shadow:var(--e-1); }
.chip.more{ background:var(--ink); color:var(--bone); border-color:var(--ink); }
/* Logo chips: the mark sits in the chip's own ink at rest and takes the
   brand's colour only on hover, so the cloud reads as one system first and
   a logo wall second. */
.chip-logo{ display:inline-flex; align-items:center; gap:9px; padding-left:13px; transition:color .2s ease, border-color .2s ease; }
.chip-logo svg{ width:18px; height:18px; flex:none; fill:currentColor; transition:fill .25s ease; }
@media (hover:hover){
  .chip-logo:hover{ color:var(--ink); border-color:color-mix(in oklab, var(--brand, var(--ink)) 40%, var(--hair)); }
  .chip-logo:hover svg{ fill:var(--brand, var(--ink)); }
}
.conn-lead{ font-size:clamp(1.25rem,2vw,1.6rem); font-weight:600; color:var(--ink);
  letter-spacing:-.02em; line-height:1.25; }
.conn-steps{ list-style:none; margin:22px 0 0; padding:0; display:grid; gap:2px; }
.conn-steps li{ display:flex; gap:14px; align-items:flex-start; padding:12px 0;
  font-size:15px; line-height:1.5; color:var(--ink-soft); border-top:1px solid var(--hair-ink); }
.conn-steps li:first-child{ border-top:0; }
.conn-steps .n{ width:24px; height:24px; border-radius:50%; background:var(--sea-wash); color:var(--sea);
  display:grid; place-items:center; font-size:12.5px; font-weight:600; flex:none; }
.channel-head{ margin-top:clamp(48px,6vw,76px); padding-top:clamp(40px,5vw,62px);
  border-top:1px solid var(--hair-ink); }

/* doors */
/* The roster row: the product's own initial-circle avatars, so "assistants
   with names" is seen rather than claimed. The names are illustrative. */
.staffrow{ display:flex; flex-wrap:wrap; gap:10px; justify-content:center;
  margin-top:clamp(26px,3vw,40px); }
.staffrow .chip{ display:inline-flex; align-items:center; gap:9px; }
.staffrow .av{ width:24px; height:24px; border-radius:50%; font-style:normal;
  display:inline-grid; place-items:center; font-size:12px; font-weight:700;
  color:#F7F4EC; background:#12344F; }

/* boss */
.bossgrid{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:clamp(30px,4.5vw,64px); align-items:center; }
.boss-p{ margin-top:18px; font-size:1.1rem; line-height:1.6; color:var(--ink-soft); }
.bossgrid h2{ margin-top:14px; }
.approve{ background:var(--bone-lift); border:1px solid var(--hair); border-radius:var(--r-lg);
  box-shadow:var(--e-2); overflow:hidden; }
.ap-top{ padding:14px 18px; border-bottom:1px solid var(--hair-ink); font-size:11.5px; font-weight:600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--ink-faint); display:flex; align-items:center; gap:9px; }
.ap-top .n{ width:20px; height:20px; border-radius:50%; background:var(--ink); color:var(--bone);
  display:grid; place-items:center; font-size:11px; }
.ap-body{ padding:18px; }
.ap-field{ display:flex; gap:12px; padding:8px 0; font-size:14px; align-items:baseline; }
.ap-field .k{ width:64px; flex:none; color:var(--ink-faint); font-size:11.5px; font-weight:600;
  letter-spacing:.06em; text-transform:uppercase; }
.ap-field .v{ color:var(--ink-2); }
.ap-field.locked .v{ display:inline-flex; align-items:center; gap:7px; color:var(--ink); }
.ap-field.locked svg{ width:13px; height:13px; color:var(--ink-faint); }
.ap-text{ margin-top:10px; padding:13px 14px; background:var(--bone-sink); border-radius:var(--r-sm);
  font-size:14px; line-height:1.55; color:var(--ink-2); border:1px dashed var(--hair-strong); }
.ap-actions{ padding:14px 18px; border-top:1px solid var(--hair-ink); display:flex; gap:10px; align-items:center; }
.ap-btn{ font-family:var(--sans); font-size:14px; font-weight:600; padding:9px 18px;
  border-radius:var(--r-sm); border:1px solid transparent; cursor:default; }
.ap-btn.yes{ background:var(--ink); color:var(--bone); }
.ap-btn.edit{ background:var(--bone-lift); color:var(--ink); border-color:var(--hair); }
.ap-hint{ margin-left:auto; font-size:12.5px; color:var(--ink-faint); }

/* pricing — three plans share one clean row; the billing mechanics sit below
   because they apply equally to every plan. */
.plansgrid{ margin-top:clamp(34px,4vw,52px); display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(14px,2vw,24px); align-items:stretch; }
.plan{ position:relative; background:var(--bone-lift); border:1px solid var(--hair); border-radius:var(--r-lg);
  padding:clamp(24px,2.6vw,32px); display:flex; flex-direction:column; box-shadow:var(--e-1); }
.plan.star{ border-color:color-mix(in oklab, var(--marina) 58%, transparent); box-shadow:var(--e-2); }
.plan-flag{ position:absolute; top:-10px; left:26px; background:var(--ink); color:var(--bone);
  font-size:11px; font-weight:600; letter-spacing:.1em; text-transform:uppercase; padding:5px 12px; border-radius:var(--r-pill); }
.plan h3,.plan h2{ font-size:1.15rem; }
.plan .tag{ margin-top:6px; font-size:14px; line-height:1.45; color:var(--ink-soft); min-height:4.35em; }
.price{ margin-top:20px; display:flex; align-items:baseline; gap:7px; }
.price .amt{ font-size:2.9rem; font-weight:600; color:var(--ink); letter-spacing:-.04em; line-height:1; }
.price .per{ font-size:14px; color:var(--ink-soft); font-weight:500; }
.price-was{ margin-top:8px; font-size:13px; color:var(--ink-faint); }
.incl{ list-style:none; margin:20px 0 0; padding:20px 0 0; border-top:1px solid var(--hair-ink);
  display:grid; gap:11px; flex:1; }
.incl li{ display:flex; gap:10px; align-items:flex-start; font-size:14.5px; line-height:1.45; color:var(--ink-2); }
.incl svg{ width:16px; height:16px; flex:none; margin-top:3px; color:var(--sea); }
.plan .btn{ margin-top:24px; width:100%; }
.plans-note{ grid-column:1 / -1; max-width:48rem; margin:24px auto 0; text-align:center; color:var(--ink-soft);
  font-size:14px; line-height:1.55; }

/* join — the last card of the day; the night sky around it does the closing */
.join{ background:transparent; position:relative; padding-block:0; }
.join > .wrap{ padding-inline:0; }
.join .inner{ margin-inline:auto; text-align:center; position:relative;
  padding:clamp(48px,7vh,92px) clamp(24px,5vw,80px);
  background:color-mix(in oklab, var(--bone) 92%, transparent);
  -webkit-backdrop-filter:blur(8px) saturate(120%); backdrop-filter:blur(8px) saturate(120%);
  border:1px solid var(--hair);
  border-radius:var(--r-panel);
  box-shadow:var(--e-3); }
.join .inner > *{ max-width:44rem; margin-inline:auto; }
.join form{ max-width:44rem; margin-inline:auto; margin-top:32px; text-align:left; }
.join .intro{ margin-top:18px; font-size:1.1rem; line-height:1.6; color:var(--ink-soft); }
.jgrid{ display:grid; grid-template-columns:1fr 1fr; gap:13px; }
.jf{ display:flex; flex-direction:column; gap:7px; }
.jf.wide{ margin-top:13px; }
.jf label{ font-size:13px; font-weight:600; color:var(--ink-2); }
.jf input,.jf textarea{ font-family:var(--sans); font-size:15.5px; color:var(--ink);
  background:var(--bone-lift); border:1px solid var(--hair-strong); border-radius:var(--r-sm);
  padding:13px 14px; width:100%; transition:border-color var(--dur-1), box-shadow var(--dur-1), background var(--dur-1); }
.jf input::placeholder,.jf textarea::placeholder{ color:var(--ink-faint); }
.jf input:focus,.jf textarea:focus{ outline:none; border-color:var(--sea);
  background:#fff; box-shadow:0 0 0 4px var(--sea-wash); }
.jf textarea{ resize:vertical; min-height:86px; line-height:1.5; }
/* The one-line why under a field. Optional fields only; it must never look
   like an error, so it keeps the label's ink at the faintest step. */
.jhint{ font-size:12.5px; line-height:1.45; color:var(--ink-faint); }
.jf .req{ color:var(--ink-faint); }
.jhp{ position:absolute; left:-9999px; width:0; height:0; overflow:hidden; }
.join .cf-turnstile{ margin-top:16px; }
.btn-go{ margin-top:20px; width:100%; background:var(--ink); color:var(--bone); box-shadow:var(--e-2); }
@media (hover:hover){ .btn-go:hover{ transform:translateY(-1px); box-shadow:var(--e-3); } }
.btn-go:active{ transform:scale(.985); }
.join .micro{ margin-top:14px; font-size:14px; color:var(--ink-soft); text-align:center; }

/* ============ FOOTER ============ */
/* ONE piece, shrink-wrapped and centred: the last small thing on the way out.
   Same glass as the nav. Shared by the homepage and the paper subpages. */
footer{ background:transparent; display:flex; justify-content:center;
  padding-inline:clamp(14px,4.5vw,76px); padding-bottom:clamp(20px,4vh,44px); }
footer .wrap{ display:inline-flex; align-items:center; justify-content:center;
  width:auto; max-width:100%; gap:clamp(18px,2.6vw,34px);
  padding:15px clamp(20px,2.4vw,30px); flex-wrap:wrap; margin-top:14px;
  border-radius:clamp(16px,1.8vw,26px); color:#12344F; }
/* The pill is glass, and glass over paper is nothing at all. The pages with no
   scene behind them give it a real ground instead. */
body.paper:not(.detail-page) footer .wrap{
  background:color-mix(in oklab, var(--bone-lift) 88%, transparent);
  border:1px solid var(--hair);
  box-shadow:0 1px 2px rgba(18,52,79,.04), 0 14px 30px -22px rgba(18,52,79,.3); }
.flinks{ display:flex; gap:18px; }
.flinks a{ font-size:14px; text-decoration:none; }
.powered{ font-size:13.5px; }
.powered b{ font-weight:600; }
/* One ink for the whole piece; hierarchy is weight, not colour. */
footer .brand, .flinks a, .powered, .powered b, footer .wm{ color:inherit; }
@media (hover:hover){ .flinks a:hover{ text-decoration:underline; text-underline-offset:3px; } }

/* ---------- reveals ----------
   Scroll-LINKED, not scroll-triggered: each component's offset, scale, and
   opacity is a pure function of where it sits in the viewport (app.js), so
   motion tracks the visitor's hand and stops when they stop.

   Deliberately NO CSS transition on .reveal anywhere in this stylesheet: the
   driver writes a value every frame, and a transition would ease toward a
   target that has already moved. The driver IS the animation. */
.reveal{ opacity:1; }
@media (prefers-reduced-motion: no-preference){
  .js .reveal{ opacity:0; transform:translate3d(0,54px,0) scale(.966); transition:none; }
  .js .reveal.in{ opacity:1; transform:none; }
}

/* backdrop-filter ignores the element's OWN opacity in Chrome, so a reveal
   parked at opacity 0 would still blur the sky behind it at full strength — a
   hard-edged frosted rectangle floating over nothing. Filters stay off until a
   reveal has arrived. !important beats whatever the component declares. */
.js .reveal:not(.in),
.js .reveal:not(.in) *{
  -webkit-backdrop-filter:none !important; backdrop-filter:none !important; }

/* ============ RESPONSIVE ============ */
@media (max-width:1000px){
  .morning,.conn,.bossgrid{ grid-template-columns:1fr; gap:34px; }
  .card.a,.card.b{ grid-column:span 12; }
  .plansgrid{ grid-template-columns:1fr; gap:18px; }
  .hero{ padding-top:clamp(92px,14vh,140px); padding-bottom:clamp(150px,32vh,340px); }
  .workplace-body{ grid-template-columns:minmax(285px,.75fr) minmax(0,1.25fr); }
  .workplace-nav{ display:none; }
  .computer-canvas{ grid-template-columns:minmax(0,1fr); }
  .computer-inspector{ display:none; }
}
@media (max-width:760px){
  .product-proof{ padding-block:82px; }
  .product-proof .wrap{ padding-inline:4px; }
  .proof-head{ padding-inline:18px; }
  .workplace{ margin-top:42px; border-radius:20px; }
  .workplace-bar{ grid-template-columns:1fr auto; min-height:54px; padding-inline:15px; }
  .workplace-project{ display:none; }
  .workplace-body{ grid-template-columns:1fr; }
  .workplace-chat{ border-right:0; border-bottom:1px solid var(--hair-ink); }
  .chat-scroll{ padding:20px 16px 24px; }
  .chat-bubble{ max-width:30rem; }
  .workplace-computer{ min-height:0; }
  .computer-canvas{ height:auto; }
  .edit-stage{ padding:12px; }
  .video-frame{ height:clamp(250px,70vw,390px); }
  .timeline{ height:132px; }
  .workplace-foot{ align-items:flex-start; flex-direction:column; gap:13px; }
  .workplace-foot > div{ justify-content:flex-start; gap:10px 14px; }
}
@media (max-width:680px){
  .navlinks{ display:none; }
  .navtoggle{ display:inline-flex; }
  .jgrid{ grid-template-columns:1fr; }
  /* The gutter stack (main + wrap + card padding) must not triple-charge the
     text column, and the display type sizes for the column that remains. */
  .hero .wrap{ padding-inline:4px; }
  /* With no card under it the headline can take the full column. */
  .hero h1{ font-size:min(3.05rem, 11.6vw); letter-spacing:-.038em; }
  .hero-lead{ margin-top:17px; font-size:1.09rem; line-height:1.5; max-width:none; }
  .hero-fine{ font-size:14.5px; }
  .destinations{ margin-top:22px; }
  body.home::after{ content:""; position:fixed; z-index:100; inset:0; background:rgba(7,20,30,.16);
    opacity:0; pointer-events:none; transition:opacity 100ms cubic-bezier(.23,1,.32,1); }
  body.home.platform-sheet-open::after{ opacity:1; pointer-events:auto; }
  .platform-popover{ --popover-x:-50%; position:fixed; z-index:110; left:50%;
    bottom:max(12px,env(safe-area-inset-bottom)); width:calc(100vw - 24px); max-height:calc(100dvh - 96px);
    padding:10px; border-radius:20px; background:#F7F3EE; overflow:auto;
    -webkit-backdrop-filter:none; backdrop-filter:none; visibility:visible; contain:layout paint;
    will-change:transform,opacity; transform:translate3d(-50%,10px,0);
    transition:opacity 90ms cubic-bezier(.23,1,.32,1), transform 120ms cubic-bezier(.23,1,.32,1); }
  .platform-popover[data-open="true"]{ transform:translate3d(-50%,0,0);
    transition-duration:130ms,170ms; }
  .platform-popover::before,.platform-popover::after{ display:none; }
  .platform-popover-head{ min-height:36px; padding:1px 2px 9px 5px; gap:10px; }
  .platform-popover-head b{ font-size:13px; }
  .platform-popover-head > span{ margin-left:auto; font-size:9px; }
  .platform-popover-close{ display:grid; flex:none; }
  .platform-popover-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); gap:2px 4px; padding-top:7px; }
  /* The route to Connections used to live on a marquee under the plaque. It
   belongs here instead: at the bottom of the list of destinations, where
   someone counting them is already asking the question it answers. */
.platform-popover-more{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  margin-top:9px; padding:11px 12px; border-radius:12px; text-decoration:none;
  background:color-mix(in oklab,var(--sea) 8%,transparent);
  color:var(--sea-deep); font-size:13px; font-weight:600;
  transition:background-color var(--dur-1) var(--ease); }
.platform-popover-more svg{ width:17px; height:17px; flex:none; fill:none;
  stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
  transition:transform var(--dur-2) var(--ease); }
@media (hover:hover){
  .platform-popover-more:hover{ background:color-mix(in oklab,var(--sea) 15%,transparent); }
  .platform-popover-more:hover svg{ transform:translateX(3px); }
}
.platform-popover-item{ gap:5px; padding:7px 4px; font-size:10.5px; }
  .platform-popover-item svg{ width:15px; height:15px; }
  .hero-cta{ margin-top:22px; }
  .hero-fine{ margin-top:14px; }
  .panel{ margin-block:clamp(40px,7vh,140px); }
  .panel.pad{ padding-block:44px; }
}
@media (max-width:460px){
  .proof-head h2{ font-size:clamp(2.45rem,12.5vw,3.35rem); }
  .workplace-live{ font-size:8.5px; }
  .workplace-live > span{ width:6px; height:6px; }
  .computer-bar{ align-items:flex-start; flex-direction:column; padding:11px 12px; gap:8px; }
  .computer-tabs{ width:100%; }
  .computer-tabs span{ flex:1; text-align:center; }
  .video-caption{ font-size:12px; }
  .plate{ scale:.78; }
}
@media (max-width:350px){
  .platform-popover-grid{ gap-inline:2px; }
  /* The route to Connections used to live on a marquee under the plaque. It
   belongs here instead: at the bottom of the list of destinations, where
   someone counting them is already asking the question it answers. */
.platform-popover-more{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  margin-top:9px; padding:11px 12px; border-radius:12px; text-decoration:none;
  background:color-mix(in oklab,var(--sea) 8%,transparent);
  color:var(--sea-deep); font-size:13px; font-weight:600;
  transition:background-color var(--dur-1) var(--ease); }
.platform-popover-more svg{ width:17px; height:17px; flex:none; fill:none;
  stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
  transition:transform var(--dur-2) var(--ease); }
@media (hover:hover){
  .platform-popover-more:hover{ background:color-mix(in oklab,var(--sea) 15%,transparent); }
  .platform-popover-more:hover svg{ transform:translateX(3px); }
}
.platform-popover-item{ gap:3px; padding-inline:2px; font-size:9.5px; }
  .platform-popover-item svg{ width:14px; height:14px; }
}

/* ============================================================
   THE SUBPAGES — paper laid on the same water
   ============================================================
   The homepage is the scene. The subpages are the document, and a document is
   read on paper: a long column of copy over moving water is the fight the
   hero already had to be lifted into the sky to avoid.

   So the harbor runs behind the whole page here too, one fixed canvas exactly
   as on the homepage, and the PAPER covers the middle. The hero and the
   closing call sit in the gaps at either end, which gives the page a shape:
   you come in off the water, you read, you go back out to it. */
.sky-band{ position:fixed; z-index:0; inset:0 0 auto; height:100vh; height:100lvh;
  overflow:hidden; pointer-events:none;
  /* The static sky is the DEFAULT, not the failure case: it is what shows in
     the moment before the renderer is up, and a dark ground under ink solved
     for daylight is the one state that cannot be allowed to flash. */
  background:
    linear-gradient(180deg, #4E7C96 0%, #5E8CA6 26%, #7FA6BC 60%, #9FBCCC 88%, #C9D9E1 100%) 0 64% / 100% 36% no-repeat,
    radial-gradient(52% 46% at 74% 76%, rgba(247,240,224,.55), transparent 70%),
    linear-gradient(180deg, #21486B 0%, #3C6E90 44%, #86ADC2 78%, #D6DFE0 100%); }
.sky-band canvas{ position:absolute; inset:0; width:100%; height:100%; display:none; }
.sky-band canvas.on{ display:block; }
.detail-page{ background:var(--bone); }
.detail-page .detail-main{ padding-top:0 !important; }
.detail-page main{ position:relative; z-index:1; }
.detail-page .detail-hero{ display:flex; align-items:center;
  min-height:clamp(560px,80svh,900px);
  padding-top:clamp(112px,16vh,180px); padding-bottom:clamp(56px,9vh,110px); }
.detail-page .detail-hero .btn-primary{ background:var(--sky-ink,var(--ink)); color:var(--sky-paper,var(--bone)); }

/* The sheet. Consecutive sections are flush, so together they read as one
   piece of paper laid on the water, with a crisp edge at each end. Crisp, not
   faded: the same rule every surface on this site follows. */
.detail-page .detail-section,
.detail-page .pricing-detail{ position:relative; background:var(--bone); }
.detail-page .detail-hero + *{ box-shadow:0 -1px 0 rgba(18,52,79,.18); }
.detail-page .detail-section:has(+ .detail-cta),
.detail-page .pricing-detail:has(+ .detail-cta){ box-shadow:0 1px 0 rgba(18,52,79,.18); }
.detail-page .detail-hero + *:has(+ .detail-cta){
  box-shadow:0 -1px 0 rgba(18,52,79,.18), 0 1px 0 rgba(18,52,79,.18); }

/* Objects on the sheet get the light the page is standing in: the same
   sun-following shadow the homepage's surfaces cast, so a card here and a card
   there are lit by one sun rather than by two different stylesheets. */
.detail-page .surface,
.detail-page .plan{
  box-shadow:var(--sun-dx) calc(var(--sun-dy) * 1.1) 72px -48px rgba(6,18,28,calc(var(--sun-cast) * .8)),
             0 2px 10px -6px rgba(6,18,28,.16); }

/* The closing call goes back out onto the water, and solves its ink there. */
.detail-page .detail-cta{ padding-block:clamp(96px,15vh,190px); border-top:0; }
.detail-page .detail-cta .btn-primary{ background:var(--sky-ink,var(--ink));
  color:var(--sky-paper,var(--bone)); border:0;
  box-shadow:0 0 0 1px color-mix(in oklab, var(--sky-paper,var(--bone)) 30%, transparent),
             calc(var(--sun-dx) * .3) calc(var(--sun-dy) * .4) 30px -18px rgba(6,18,28,.7); }

/* ============================================================
   SUBPAGES — privacy, terms, thanks, 404. Plain warm-shell paper
   with the same chrome; body background comes from the base rule.
   ============================================================ */
.paper{ min-height:100svh; display:flex; flex-direction:column; }
.paper main{ padding-top:clamp(96px,14vh,150px); flex:1; display:flex; flex-direction:column; }
.paper main > .simple{ flex:1; }

/* Product and connections pages. These hold the deeper explanation that made
   the homepage feel like a deck. The layout is editorial first: long rules,
   numbered rows, and only the product surfaces that genuinely explain UI. */
.detail-page{ background:#F7F3EE; }
.detail-main{ padding-top:clamp(118px,15vh,164px) !important; }
.detail-hero{ padding-bottom:clamp(72px,9vw,116px); }
.detail-copy{ max-width:48rem; }
.detail-copy h1{ margin-top:17px; font-size:clamp(3rem,7.3vw,6.4rem); line-height:.94; letter-spacing:-.06em; }
.detail-copy h2{ margin-top:15px; font-size:clamp(2.25rem,4.9vw,4.3rem); line-height:1; letter-spacing:-.048em; }
.detail-copy > p{ margin-top:22px; max-width:41rem; color:var(--ink-soft); font-size:clamp(1.08rem,1.8vw,1.3rem); line-height:1.58; }
.detail-copy > p + p{ margin-top:15px; }
.detail-actions{ display:flex; flex-wrap:wrap; gap:12px; margin-top:32px; }
/* No rules between sections. The homepage divides with space and this page
   should read as the same site; a full-bleed hairline is the flattest device
   here and it was the only one left. */
.detail-section{ padding-block:clamp(76px,10vw,132px); }
.detail-split{ display:grid; grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr); gap:clamp(44px,8vw,104px); align-items:start; }
.detail-points{ margin-top:36px; display:grid; gap:24px; }
.detail-points > div{ padding-top:20px; border-top:1px solid var(--hair-ink); }
.detail-points h3,.staff-editorial h3{ font-size:1.08rem; }
.detail-points p,.staff-editorial p{ margin-top:7px; color:var(--ink-soft); font-size:15px; line-height:1.58; }
.capability-list{ margin-top:clamp(50px,7vw,86px); border-top:1px solid var(--hair-strong); }
.capability-list article{ display:grid; grid-template-columns:70px minmax(0,1fr); gap:clamp(24px,4vw,60px); padding:clamp(25px,3.6vw,42px) 0; border-bottom:1px solid var(--hair-strong); }
.capability-list article > span,.access-number{ color:var(--sea-deep); font-size:12px; font-weight:650; letter-spacing:.12em; }
.capability-list h3{ font-size:clamp(1.4rem,2.5vw,2rem); }
.capability-list p{ margin-top:8px; max-width:52rem; color:var(--ink-soft); font-size:1.03rem; line-height:1.58; }
.detail-trust{ margin-top:24px; max-width:52rem; color:var(--ink-soft); font-size:14px; line-height:1.55; }
.approval-split{ align-items:center; }
.staff-editorial{ border-top:1px solid var(--hair-strong); }
.staff-editorial > div{ padding:25px 0; border-bottom:1px solid var(--hair-strong); }
.detail-cta{ padding-block:clamp(76px,10vw,128px); border-top:1px solid var(--hair-strong); text-align:center; }
.detail-cta .detail-copy{ margin-inline:auto; }
.detail-cta .detail-copy > p{ margin-inline:auto; }
.detail-cta .btn{ margin-top:30px; }

.access-list{ border-top:1px solid var(--hair-strong); }
.access-list article{ display:grid; grid-template-columns:74px minmax(0,1fr); gap:clamp(22px,4vw,60px); padding:clamp(34px,5vw,62px) 0; border-bottom:1px solid var(--hair-strong); }
.access-list h2{ font-size:clamp(2rem,4vw,3.5rem); letter-spacing:-.045em; }
.access-list p{ margin-top:12px; max-width:52rem; color:var(--ink-soft); font-size:clamp(1rem,1.5vw,1.15rem); line-height:1.6; }
.access-marks{ margin-top:18px; }
.connection-cloud{ align-content:start; padding-top:8px; }
.connection-steps{ list-style:none; margin:0; padding:0; border-top:1px solid var(--hair-strong); }
.connection-steps li{ display:grid; grid-template-columns:34px minmax(0,1fr); gap:18px; padding:25px 0; border-bottom:1px solid var(--hair-strong); }
.connection-steps span{ width:28px; height:28px; border-radius:50%; display:grid; place-items:center; background:var(--sea-wash); color:var(--sea-deep); font-size:12px; font-weight:650; }
.connection-steps p{ color:var(--ink-soft); font-size:1rem; line-height:1.58; }
.pricing-hero{ padding-bottom:clamp(56px,7vw,88px); }
.pricing-detail{ padding-block:clamp(60px,8vw,96px); border-top:1px solid var(--hair-strong); }
.pricing-detail .plansgrid{ margin-top:0; }

@media (max-width:760px){
  .detail-main{ padding-top:112px !important; }
  .detail-copy h1{ font-size:clamp(2.9rem,14vw,4.6rem); }
  .detail-split{ grid-template-columns:1fr; gap:42px; }
  .detail-section{ padding-block:64px; }
  .capability-list article,.access-list article{ grid-template-columns:42px minmax(0,1fr); gap:14px; }
  .detail-page footer .flinks{ width:100%; justify-content:center; }
}

.legal{ padding-bottom:clamp(48px,8vh,96px); }
.legal-prose{ max-width:64ch; }
.legal-prose h1{ font-size:clamp(2.2rem,4.6vw,3.4rem); margin-bottom:6px; }
.legal-updated{ font-size:12px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-faint); margin-bottom:26px; }
.legal-prose h2{ margin-top:34px; margin-bottom:8px; font-size:clamp(1.2rem,2vw,1.5rem); }
.legal-prose p, .legal-prose li{ margin-top:12px; color:var(--ink-soft); font-size:1.03rem; line-height:1.66; }
.legal-prose ul{ margin-top:8px; padding-left:1.2em; }
.legal-prose li{ margin-top:8px; }
.legal-prose strong{ color:var(--ink); font-weight:600; }
.legal-prose a{ color:var(--sea); }
.back-link{ display:inline-flex; align-items:center; gap:.5em; margin-top:36px;
  font-weight:500; font-size:15px; color:var(--sea); text-decoration:none; }

.simple{ min-height:56vh; display:flex; align-items:center; text-align:center;
  padding-bottom:clamp(48px,8vh,96px); }
.simple .wrap > *{ margin-inline:auto; }
.simple h1{ font-size:clamp(2.2rem,4.6vw,3.4rem); margin-top:14px; }
.simple p{ margin-top:16px; font-size:1.08rem; line-height:1.6; color:var(--ink-soft);
  max-width:44ch; margin-inline:auto; }
.simple .btn{ margin-top:28px; }

/* Reduced motion: the driver never runs, so the page lands on its static
   daylight state. The panels and chrome are already legible on it; only the
   sky needs to be told which frame to hold. Stays last in this stylesheet. */
@media (prefers-reduced-motion: reduce){
  /* The same one honest hour the no-renderer tier lands on, horizon included:
     the hero's composition is built around a horizon, and a sky without one is
     not a calmer version of this page, it is a different layout. */
  .home{ background:#DCE6EC; }
  .l-astro,.l-nautical,.l-civil,.l-day{ opacity:1; }
  .stars{ opacity:0; }
  .sun{ opacity:1; transform:translate3d(0,-4vh,0) scale(1.06); }
  .sky::after{ content:""; position:absolute; left:0; right:0;
    top:calc(var(--sky-ot,0px) + 64lvh); bottom:0;
    background:linear-gradient(180deg,
      #C9D9E1 0%, #9FBCCC 3%, #7FA6BC 26%, #5E8CA6 62%, #4E7C96 100%); }
  .platform-word{ transform:none !important; opacity:0; transition:opacity .2s ease; }
  .platform-word.is-in{ opacity:1; }
  .platform-popover{ transform:translate3d(var(--popover-x),0,0); transition:opacity 150ms ease, visibility 0s linear 150ms; }
  .platform-hover[data-open="true"] .platform-popover{ transform:translate3d(var(--popover-x),0,0); transition-delay:0s; }
}

/* ============================================================
   ON THE SKY
   ============================================================
   Some of the page has no card under it. It stands on the harbor, and its ink
   is not styled but SOLVED: app.js reads the rendered scene behind each block
   and hands back an ink, a hairline, an accent, and however much backing wash
   the contrast actually needs. At noon that is deep ink and no wash at all; at
   two in the morning it is Shell over the starfield. The flip between them
   lands where the wash is already near its strongest, so it is covered.

   Every colour below reads through a custom property with the static daylight
   value as its fallback, which is exactly what a visitor with no JS, no
   WebGPU, or reduced motion gets. */
.onsky{ position:relative; color:var(--sky-ink,var(--ink)); }
.onsky h1,.onsky h2,.onsky h3,.onsky p,.onsky li,.onsky a,
.onsky b,.onsky strong,.onsky em,.onsky span,.onsky .kicker{ color:inherit; }
/* Two things carry the ink over a live scene, and the smaller one does most of
   the work.

   The HALO is a soft glow in the opposite ink, hugging every glyph. It costs
   nothing, it never reads as a slab laid over the picture, and because it sits
   within a few pixels of each stroke it fixes exactly the contrast that
   matters. This is the one that makes type on water possible at all.

   The WASH is a broad breath behind the whole block, for the hours when the
   halo alone cannot get there. It is centred on the block and generous, since
   a wash that misses the end of a line is worse than no wash: it leaves the
   page looking treated and still unreadable. */
.onsky{ text-shadow:0 0 var(--sky-halo-far,0px) var(--sky-glow,transparent),
                    0 0 var(--sky-halo-near,0px) var(--sky-glow,transparent);
  transition:color .45s linear, text-shadow .45s linear; }
/* The halo is for ink sitting directly on the scene. Anything that brought its
   own ground already has its contrast solved, and a glow inherited onto a label
   on a solid pill just reads as a blurry button. */
.onsky .btn,
.onsky button,
.onsky input,
.onsky textarea{ text-shadow:none; }
/* The ellipse's radii are HALF the box, so the wash reaches nothing exactly at
   the box's own edges. Any larger and the gradient is still opaque where the
   background stops painting, which draws a hard-edged rectangle across the
   scene: the one thing this is here to avoid. The box is inset generously
   instead, so the fade happens outside the type rather than through it. */
.onsky::before{ content:""; position:absolute; z-index:-1; pointer-events:none;
  inset:-42% -24%;
  background:radial-gradient(50% 50% at 50% 50%, var(--sky-wash,transparent) 0%,
                             var(--sky-wash,transparent) 34%,
                             var(--sky-wash-mid,transparent) 62%, transparent 100%);
  opacity:var(--sky-scrim,0); transition:opacity .45s linear; }

/* The buttons are solved like everything else, and then given an edge in the
   opposite ink. Solved contrast guarantees the pill clears its backdrop, but a
   pale pill on a pale sky still reads as a ghost: the ring is what makes it an
   object. */
.onsky .btn-primary{ background:var(--sky-ink,var(--ink)); color:var(--sky-paper,var(--bone));
  border:0; box-shadow:0 0 0 1px color-mix(in oklab, var(--sky-paper,var(--bone)) 30%, transparent),
                       calc(var(--sun-dx) * .3) calc(var(--sun-dy) * .4) 30px -18px rgba(6,18,28,.7); }
.onsky .btn-soft{ background:color-mix(in oklab, var(--sky-paper,var(--bone)) 10%, transparent);
  color:var(--sky-ink,var(--ink));
  border:1px solid color-mix(in oklab, currentColor 48%, transparent); box-shadow:none; }
@media (hover:hover){
  .onsky .btn-soft:hover{ background:color-mix(in oklab, currentColor 10%, transparent); }
}

/* ============================================================
   THE PAGE AS OBJECTS ON WATER
   ============================================================
   The old page was one long sheet with the sky showing in the gutters, which
   meant the day it is built around was never actually visible. Each section is
   its own object now, with open water between them. */

.product-proof{ background:none; border:0; border-radius:0; box-shadow:none;
  -webkit-backdrop-filter:none; backdrop-filter:none;
  margin-block:clamp(48px,9vh,132px); padding-block:0; }
.proof-head{ max-width:52rem; margin-inline:0; text-align:left; }
.proof-head .kicker{ justify-content:flex-start; }
.proof-head h2{ font-size:clamp(2.8rem,6.4vw,6rem); letter-spacing:-.05em; line-height:.95; }
.proof-head p{ margin-inline:0; max-width:44rem; }
.product-proof .proof-close{ max-width:44rem; margin-inline:0; text-align:left;
  font-size:clamp(1.1rem,1.7vw,1.42rem); line-height:1.5; letter-spacing:-.015em; }

/* The workplace stays a lit window: the one object on the page that is meant to
   look like software, floating over the water it is lit by. */
.workplace{ margin-top:clamp(44px,6vw,80px);
  box-shadow:calc(var(--sun-dx) * 1.5) calc(var(--sun-dy) * 1.7) 116px -58px rgba(6,18,28,var(--sun-cast)),
             0 8px 26px -12px rgba(6,18,28,.26),
             0 0 0 1px rgba(18,52,79,.14); }

/* Pricing: the heading on the water, the plans as three floating cards. */
#pricing.panel{ background:none; border:0; box-shadow:none; border-radius:0;
  -webkit-backdrop-filter:none; backdrop-filter:none; padding-block:0;
  margin-block:clamp(60px,11vh,150px); }
#pricing .sec-head{ max-width:44rem; }
#pricing .plansgrid{ margin-top:clamp(32px,4vw,52px); }
#pricing .plan{ background:color-mix(in oklab, var(--bone-lift) 96%, transparent);
  box-shadow:var(--sun-dx) calc(var(--sun-dy) * 1.2) 84px -50px rgba(6,18,28,var(--sun-cast)),
             0 2px 10px -4px rgba(6,18,28,.18); }

/* The waitlist is the page's last object, and the only one that asks for
   anything, so it gets the most presence. */
#join.pad{ background:none; border:0; box-shadow:none; border-radius:0;
  -webkit-backdrop-filter:none; backdrop-filter:none; padding-block:0;
  margin-block:clamp(60px,11vh,150px); }
#join .inner{ max-width:900px; margin-inline:auto;
  padding:clamp(34px,4.4vw,64px) clamp(26px,4vw,64px);
  background:color-mix(in oklab, var(--bone-lift) 96%, transparent);
  border:1px solid var(--hair); border-radius:var(--r-panel);
  box-shadow:calc(var(--sun-dx) * 1.4) calc(var(--sun-dy) * 1.7) 116px -58px rgba(6,18,28,var(--sun-cast)),
             0 4px 16px -8px rgba(6,18,28,.2); }

@media (max-width:900px){
  .hero-capabilities{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:22px 26px; }
  .hero-capabilities li + li{ box-shadow:none; }
  .hero-copy{ max-width:none; }
}
@media (max-width:600px){
  .hero-capabilities{ grid-template-columns:1fr; }
}

/* ============================================================
   THE SWITCHBOARD
   ============================================================
   Every other object on this page floats ON the water. This one is the page
   looking OUT at it: the one pane that is night whatever hour the sky is
   keeping, because the thing it is about is the world outside the workplace.
   Deep harbour, one warm light in the middle, the mark's own three colours.

   Everything with an edge is DOM and SVG at device resolution: the marks, the
   names, the rails, and the light that travels them. public/flow.js draws only
   the field behind all of that. It ran at a fraction of device resolution and
   an earlier version had it drawing the lanes and a glow around every mark
   too, which put a soft low-resolution copy of every curve half a pixel off
   its own crisp one. A field is for the ground; it is not for anything that
   also has an edge.

   Marks and rails are placed by percentages of one 780x670 box and
   tools/gen-flow.mjs writes them all from one set of numbers, so a mark and
   its rail cannot drift apart. */
.connect{ padding-block:clamp(52px,8vh,104px); }
/* Wider than the page's other objects: the picture is the argument here, and
   at the default width it was drawn small enough to need reading twice. */
.connect .wrap{ max-width:1280px; }
.connect-plaque{ position:relative; display:grid; grid-template-columns:minmax(0,.62fr) minmax(0,1fr);
  gap:clamp(24px,3vw,52px); align-items:center;
  padding:clamp(28px,3.4vw,54px);
  border-radius:clamp(18px,2vw,28px);
  /* Flat, and exactly the colour the shader falls to at its own border, so the
     pane reads as one surface whether the field is running or not. Near black
     on purpose: a floor is only lit if it was unlit to begin with. */
  background:#05090E;
  border:1px solid rgba(150,192,214,.15);
  box-shadow:calc(var(--sun-dx) * .8) var(--sun-dy) 92px -54px rgba(3,10,16,.5),
             0 3px 14px -6px rgba(3,10,16,.45),
             inset 0 1px 0 rgba(198,224,238,.07);
  overflow:hidden; }
/* With no canvas the pane keeps the same shape of light, standing still. */
.connect-plaque.no-light{ background-image:radial-gradient(76% 88% at 47% 50%, #0C1720 0%, #05090E 74%); }

.connect-copy .kicker{ color:#79BBD6; }
.connect-copy h2{ margin-top:14px; font-size:clamp(2.1rem,3.8vw,3.3rem); letter-spacing:-.045em; line-height:1.02;
  color:#F7F4EC; }
.connect-lines{ list-style:none; margin:26px 0 0; padding:0; display:grid; gap:15px; max-width:31rem; }
.connect-lines li{ position:relative; padding-left:23px; font-size:clamp(1rem,1.2vw,1.1rem); line-height:1.5;
  color:#BFD3DD; }
.connect-lines li::before{ content:""; position:absolute; left:2px; top:.6em; width:7px; height:7px; border-radius:50%;
  background:#4C87A4; }
.connect-copy .btn{ margin-top:30px; }
.connect .btn-soft{ background:rgba(247,244,236,.055); color:#F7F4EC;
  border-color:rgba(160,200,220,.3); box-shadow:none; }
@media (hover:hover){
  .connect .btn-soft:hover{ background:rgba(247,244,236,.11); border-color:rgba(160,200,220,.5); }
}

.flow-fig{ margin:0; display:grid; justify-items:center; position:relative; z-index:1; }
.connect-copy{ position:relative; z-index:1; }
.flow{ position:relative; width:100%; max-width:760px; aspect-ratio:780/700; container-type:inline-size;
  -webkit-user-select:none; user-select:none; }

/* The field. It fades in under its own hand once the first frame is on the
   canvas, so a machine that cannot draw it never shows an empty black box. */
.flow-light{ position:absolute; inset:0; width:100%; height:100%; display:block;
  opacity:0; transition:opacity .9s ease; }
.flow-light.on{ opacity:1; }

/* ---- the rails, and the light that travels them ---- */
.flow-rails{ position:absolute; inset:0; width:100%; height:100%; overflow:visible; fill:none; }
.flow-rails path{ vector-effect:non-scaling-stroke; }
.rails path{ stroke:url(#flowLit); stroke-width:1; opacity:.62; transition:opacity .22s ease; }
/* One dash on a 211-long pattern: at offset 11 it sits just before the start of
   a rail and at -100 just past its end, so exactly one spark is ever on a line
   and it always runs the whole way. Quiet on purpose. This is a diagram, and a
   comet on every wire is a screensaver. */
.sparks path{ stroke:url(#flowLit); stroke-width:1.5; stroke-linecap:round;
  stroke-dasharray:7 200; stroke-dashoffset:11; opacity:0;
  animation-delay:var(--d,0s); animation-iteration-count:infinite; animation-timing-function:linear; }
.sparks path.in{ animation-name:spark-in; animation-duration:9s; }
.sparks path.out{ animation-name:spark-out; animation-duration:19.8s; }
.sparks{ transition:opacity .22s ease; }
@keyframes spark-in{
  0%     { stroke-dashoffset:11;   opacity:0; }
  2%     { opacity:.62; }
  9.6%   { opacity:.62; }
  11.7%  { stroke-dashoffset:-100; opacity:0; }
  100%   { stroke-dashoffset:-100; opacity:0; }
}
@keyframes spark-out{
  0%     { stroke-dashoffset:11;   opacity:0; }
  1%     { opacity:.62; }
  5.05%  { opacity:.62; }
  6.06%  { stroke-dashoffset:-100; opacity:0; }
  100%   { stroke-dashoffset:-100; opacity:0; }
}

/* ---- the labels above each column ---- */
.flow-head{ position:absolute; transform:translate(-50%,-50%); white-space:nowrap;
  font-size:clamp(10px,1.55cqw,12px); font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:#89A5B4; }
/* The right-hand headings hang off the left edge of their circles, so the
   three groups line up with each other and not with the width of their own
   words. */
.flow-head.to{ transform:translate(-2.7cqw,-50%); }

/* ---- the staff ---- */
/* The mark, at size, and nothing else. It had a pale pill and a wordmark on it
   and read as a sticker stuck on the picture. It is the one light in here, so
   it is the one thing that gets to be the logo: the shader lays a band of its
   own sand right against this rim and a long falloff behind that, which is
   what separates a dark mark from dark water. */
.flow-core{ position:absolute; transform:translate(-50%,-50%);
  width:16.41cqw; height:16.41cqw; border-radius:50%; display:block; }
.flow-core svg{ display:block; width:100%; height:100%; }

/* ---- everything the staff reaches ---- */
.flow-node{ position:absolute; transform:translate(-50%,-50%); width:5.385cqw; height:5.385cqw;
  min-width:30px; min-height:30px; border-radius:50%;
  display:grid; place-items:center; color:#DCE8EF;
  background:#0E2230; border:1px solid rgba(150,192,214,.24);
  transition:transform .22s cubic-bezier(.23,1,.32,1), opacity .22s ease,
             color .22s ease, border-color .22s ease; }
.flow-node svg{ width:52%; height:52%; fill:currentColor; }
.flow-node.stroke svg{ fill:none; stroke:currentColor; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round; }
.flow-node i{ position:absolute; white-space:nowrap; font-style:normal; font-size:clamp(11px,1.75cqw,13.5px);
  font-weight:600; letter-spacing:-.005em; color:#D3E1E9; transition:color .22s ease; }
.flow-node.from i{ right:calc(100% + 9px); top:50%; transform:translateY(-50%); }
.flow-node.to i{ left:calc(100% + 9px); top:50%; transform:translateY(-50%); }
.flow-node.out{ color:#8FCBE4; border-color:rgba(92,169,200,.36); }

/* Where the next name in the column would have been. The picture shows five of
   fourteen and says so, rather than leaving the count to the prose beside it. */
.flow-more{ position:absolute; transform:translateY(-50%); white-space:nowrap;
  font-size:clamp(10px,1.55cqw,12.5px); font-weight:500; letter-spacing:-.005em; color:#7E96A4; }

/* ---- the line under the picture ---- */
.flow-caption{ display:grid; width:100%; max-width:46rem; margin-top:clamp(12px,1.6vw,20px);
  text-align:center; min-height:4.35em; }
.flow-caption span{ grid-area:1/1; align-self:start; font-size:clamp(.92rem,1.05vw,1rem); line-height:1.45;
  color:#93ACBA; opacity:0; transition:opacity .2s ease; }
.flow-caption .cap-default{ opacity:1; }

/* ---- one relationship at a time ----
   The traffic settles so the one connection under the pointer can be read.
   Group opacity, not the path's own: a keyframe beats any declaration we could
   write against it, and it also keeps every clock running, so letting go does
   not fire all fifteen sparks at once. */
.flow-fig[data-hot] .sparks{ opacity:0; }
.flow-fig[data-hot] .rails path{ opacity:.16; }
.flow-fig[data-hot] .flow-node,.flow-fig[data-hot] .flow-more{ opacity:.34; }
.flow-fig[data-hot] .rails path.is-hot{ opacity:1; stroke:#CDE7F5; }
.flow-fig[data-hot] .flow-node.is-hot{ opacity:1; transform:translate(-50%,-50%) scale(1.1);
  color:var(--brand, #EAF3F8); border-color:color-mix(in oklab, var(--brand, #A9CFE2) 60%, transparent); }
.flow-fig[data-hot] .flow-node.is-hot i{ color:#F7F4EC; }
.flow-fig[data-hot] .cap-default{ opacity:0; }
.flow-caption span.is-hot{ opacity:1; }

@media (prefers-reduced-motion: reduce){
  .flow-light{ transition:none; }
  .sparks{ display:none; }
  .rails path{ opacity:.72; }
}

@media (max-width:960px){
  .connect-plaque{ grid-template-columns:1fr; gap:clamp(28px,4vw,44px); }
  .connect-lines{ max-width:none; }
}
/* A phone is a column, so the picture becomes one. Fifteen discs and their
   names do not fit across 335 points at any size worth reading, and shrinking
   them until they do turns a diagram into a spatter of dots.

   Nothing is duplicated to do it: the marks stop being placed by percentage
   and fall into a two-column grid, and the group each of them already carries
   re-orders the same DOM into the same sentence read downwards. The mark sits
   between the doors and the reach, where it belongs.

   A grid, not a wrapping row of pills. Centred pills wrapped 3 and 1, which
   left an orphan under every group and read as a bag of buttons rather than a
   list of connections. Two columns line the names up, and each item keeps the
   disc-and-name it has on a desktop instead of becoming a different object.

   The field goes with the layout. Its one source is measured from the mark,
   and the mark is now a row in a list, so the canvas comes out and the pane
   keeps a still gradient. Hiding it also stops the loop: the driver runs only
   while the canvas is on screen, and this one never is. */
@media (max-width:680px){
  .connect-plaque{ background-image:radial-gradient(88% 40% at 50% 40%, #101F2A 0%, #05090E 78%); }
  .flow-light,.flow-rails{ display:none; }
  .flow{ max-width:none; aspect-ratio:auto;
    display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:13px 14px; align-items:center; }
  .flow-head{ position:static; transform:none; grid-column:1 / -1; text-align:left;
    margin:12px 0 -5px; padding-top:14px; border-top:1px solid rgba(150,192,214,.13);
    font-size:10px; letter-spacing:.09em; }
  .flow-head.from{ margin-top:0; padding-top:0; border-top:0; }
  /* The mark keeps its size: it is the one thing in this column that is not a
     row, and it is what the two halves of the list hinge on. */
  .flow-core{ position:static; transform:none; grid-column:1 / -1; justify-self:center;
    width:62px; height:62px; margin:12px 0 10px; }
  /* justify-items, explicitly: the desktop rule sets place-items:center to put a
     mark in the middle of its disc, and left alone it would centre each name in
     the middle of its own column, half a screen from the icon it belongs to. */
  .flow-node{ position:static; transform:none; width:auto; height:auto; min-width:0; min-height:0;
    border:0; background:none; border-radius:0; box-shadow:none;
    display:grid; grid-template-columns:32px minmax(0,1fr);
    align-items:center; justify-items:start; gap:11px; }
  .flow-node svg{ box-sizing:border-box; width:32px; height:32px; padding:8px; border-radius:50%;
    background:#0E2230; border:1px solid rgba(150,192,214,.24); }
  .flow-node.stroke svg{ padding:7px; }
  .flow-node i,.flow-node.from i,.flow-node.to i{ position:static; transform:none;
    inset:auto; display:block; font-size:13px; overflow:hidden; text-overflow:ellipsis; }
  /* The more-line is written before the marks so it can be placed by percentage
     on a desktop, so it needs an order of its own to land after them here. */
  .flow-more{ position:static; transform:none; padding-left:43px; font-size:13px; }
  .flow-head.g-in{ order:1; }    .flow-node.g-in{ order:2; }
  .flow-core{ order:3; }
  .flow-head.g-pub{ order:4; }   .flow-node.g-pub{ order:5; }   .flow-more.g-pub{ order:6; }
  .flow-head.g-reach{ order:7; } .flow-node.g-reach{ order:8; }
  .flow-head.g-build{ order:9; } .flow-node.g-build{ order:10; }
  .flow-fig[data-hot] .flow-node{ opacity:1; }
  .flow-caption{ min-height:0; margin-top:22px; padding-top:16px;
    border-top:1px solid rgba(150,192,214,.13); text-align:left; }
}

/* ============================================================
   PHONES: THE SCENE IS THE OPENING, THE PAGE IS PAPER
   ============================================================
   Last in the file on purpose. These have to beat the floating-object rules
   above, which deliberately strip the background off every section so the
   water can show through; on a phone that is the wrong trade. */
@media (max-width:680px){
  /* ---- the page below the scene is paper ----
     A phone is a column of words held close to the face. Floating that column
     over live water costs legibility on every line of it, and legibility is
     what the page is for; the art can have the opening and the reader can have
     the rest. app.js sizes the scene to end exactly where the plaque begins.

     It is also the safer construction: a fixed, full-page canvas under a
     scrolling document is the shape iOS composites worst, and the strips of
     stale colour that turned up on a real phone came from asking for it. */
  /* The sheet runs edge to edge and the sections are flush, so the paper is
     one piece rather than a stack of slabs with the body colour between them.
     The gutter moves from main to the wraps to make that possible. */
  .home main{ position:relative; z-index:1; padding-inline:0; }
  .home main .wrap{ padding-inline:20px; }
  .hero .wrap{ padding-inline:20px; }
  /* The paper takes a few per cent of whatever the sky is doing, so a flat
     field on a phone is still part of the day: warm under a sunset, cool at
     night, near enough to Warm Shell at noon that nobody would name it. */
  .home{ --paper:color-mix(in oklab, var(--bone) 95%, var(--chrome, #B9CDD8)); }
  .capabilities,
  .connect,
  .product-proof,
  .home #pricing.panel,
  .home #join.pad,
  .home footer{ position:relative; background:var(--paper); margin-block:0; }

  /* The sheet comes UP out of the water rather than starting on a cut. The
     scene runs on behind this band (app.js extends it by the same amount) and
     the paper arrives over it, so there is a real moment of the page emerging
     instead of a hard edge with nothing on either side of it. No body text
     lives in the band; the bullets begin where it is fully opaque. */
  .capabilities{ box-shadow:none; background:none;
    background-image:linear-gradient(180deg,
      color-mix(in oklab, var(--paper) 0%, transparent) 0,
      color-mix(in oklab, var(--paper) 58%, transparent) 72px,
      var(--paper) 150px);
    /* The first bullet begins well clear of the fade. Reading the opening line
       of the page through a translucent band is exactly the trade this whole
       layout exists to stop making. */
    padding-top:198px; padding-bottom:clamp(8px,2vh,20px); margin-top:0; }
  /* The one dark card on the sheet. Its gutter is paper like everything else
     below the opening, or the page reads as a stack of slabs with the body
     colour showing between them, which is the shape this whole layout exists
     to stop. */
  .connect{ padding-block:clamp(40px,7vh,72px) 0; }
  .product-proof{ padding-block:clamp(52px,9vh,92px) 0; }
  .home #pricing.panel{ padding-block:clamp(56px,9vh,96px) 0; }
  .home #join.pad{ padding-block:clamp(52px,8vh,88px) clamp(40px,6vh,64px); }
  .home #join .inner{ padding:clamp(26px,5vw,36px) clamp(20px,4vw,28px);
    box-shadow:0 18px 40px -30px rgba(6,18,28,.4); }
  .home .proof-close{ margin-top:clamp(30px,5vh,52px); }
  /* Paper has to reach past the browser's own bottom bar, or the page appears
     to end on the sky colour the status area at the TOP needs the body painted
     with. Extra room below the pill, not a second background. */
  .home footer{ padding-bottom:max(104px, calc(env(safe-area-inset-bottom) + 88px)); }
  .home footer .wrap{ background:color-mix(in oklab, var(--bone-lift) 88%, transparent);
    border:1px solid var(--hair);
    box-shadow:0 1px 2px rgba(18,52,79,.04), 0 14px 30px -22px rgba(18,52,79,.3); }

  /* On paper the plaque has nothing to float above, so it stops being a card
     and becomes what it always was: four things the staff does, set at a size
     someone can actually read on a phone. */
  .capabilities{ margin-top:0; padding-top:clamp(26px,5vh,40px);
    padding-bottom:clamp(8px,2vh,20px); }
  .hero-capabilities{ grid-template-columns:1fr; border-radius:0; border:0;
    background:none; box-shadow:none;
    -webkit-backdrop-filter:none; backdrop-filter:none; }
  .hero-capabilities li{ padding:20px 2px; font-size:16.5px;
    line-height:1.5; font-weight:450; }
  .hero-capabilities li b{ font-size:19px; margin-bottom:6px; }
  .hero-capabilities li + li{ box-shadow:none; border-top:1px solid var(--hair-ink); }

  /* Everything on PAPER stops solving its ink, because there is nothing left to
     solve it against. The destinations are the exception: they are still out on
     the water with the hero, and forcing deep ink on them there leaves them
     unreadable over a night sea. */
  .home .onsky:not(.hero-copy):not(.destinations){ color:var(--ink); text-shadow:none; }
  .home .onsky:not(.hero-copy):not(.destinations)::before{ display:none; }
  .proof-head p,.proof-close,.plans-note{ color:var(--ink-2); }

  /* A fixed noise layer over a scrolling page is another thing iOS tiles
     badly, and it is five per cent of one texture. */
  .grain{ display:none; }
}
