/* styles.css — jaydenbruck.com
   ---------------------------------------------------------------------------
   Token set, elevation ladder, easing pair, glass frame, reveal primitive,
   letter motion and the phone are Ola's own, taken from tryola.ai's
   ola.css, home.css and letters.css, so this page and tryola.ai are the same
   material. The button system is Poke's depth-button-v2. The named-token
   aliasing and the touch-target expander are x.ai's.

   Redesign of 15 October 2026: fewer things, more room. No eyebrows, no
   numbered sections, no chips. One idea per screen, headings at Ola's own
   sizes, and the only moving things are the headline, the recording and the
   signature.
   --------------------------------------------------------------------------- */

/* ===========================================================================
   1. TOKENS
   ola.css :root, plus a small set of additions this page needs. Every
   functional token aliases a named one, x.ai's rule, so a re-theme is one
   line per name rather than a search across the file.
   =========================================================================== */

:root {
  /* --- ground and ink, ola.css --- */
  --ground:         #F7F6F4;
  --ground-deep:    #EDECEA;
  --ground-dark:    #0C0D10;
  --ground-dark-2:  #040507;
  --ink:            #141519;
  --ink-body:       #5C606A;
  --ink-quiet:      #62656D;
  --hairline:       rgba(0, 0, 0, 0.08);
  --hairline-firm:  rgba(0, 0, 0, 0.14);
  --glass-edge:     rgba(0, 0, 0, 0.10);
  --glass-edge-lit: rgba(0, 0, 0, 0.22);
  --inner-light:    rgba(255, 255, 255, 0.90);
  --shadow:         rgba(24, 28, 38, 0.14);
  --shadow-soft:    rgba(24, 28, 38, 0.08);
  --ink-on-deep:    #F2F3F5;
  --ink-on-deep-2:  #9EA3AB;

  --sans: "InterVariable", "Inter Fallback", -apple-system, BlinkMacSystemFont,
          "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* --- type scale. The hero, then ola.css's own --h2, --lede and --quote
         steps, so a heading here is the size of a heading on tryola.ai --- */
  --say:     clamp(40px, 6vw, 88px);    /* the hero, before it is fitted */
  --h2:      clamp(34px, 4.6vw, 64px);  /* section headings */
  --vision:  clamp(26px, 3.1vw, 44px);  /* his words, set as a statement */
  --lede:    clamp(18px, 1.5vw, 22px);  /* the line under a heading */
  --field:   17px;
  --micro:   13px;

  /* --- measure and rhythm, ola.css --- */
  --measure: 1100px;
  --wide:    1240px;
  --gutter:  24px;
  --band:    clamp(96px, 14vh, 168px);

  --field-h: 62px;
  --radius:  999px;      /* the pill, everywhere */
  --radius-card: 20px;
  --header-h: 54px;

  /* elevation: alpha falls as blur and offset rise, tinted cool rather than
     black, closed by an inset white top light so a surface reads as lit and
     not merely raised. ola.css --ladder-low, verbatim. */
  --ladder-low:
      0 0.87px  3.08px  0 rgba(183, 181, 203, 0.31),
      0 4.37px  6.16px  0 rgba(183, 181, 203, 0.27),
      0 9.18px  8.01px  0 rgba(183, 181, 203, 0.16),
      0 16.61px 9.24px  0 rgba(183, 181, 203, 0.05),
      inset 0 3px 14px 0 rgba(255, 255, 255, 0.92);
  /* ola.css --ladder-lite: the photographs sit on it */
  --ladder-lite:
      0 1px 2px rgba(0, 0, 0, 0.035),
      0 3px 8px rgba(0, 0, 0, 0.035),
      0 8px 28px rgba(0, 0, 0, 0.043);

  /* Poke's card: three ambient tiers at rest, and a hover that adds a
     fourth glow layer rather than darkening the first three */
  --card-border:       #E2E1DE;
  --card-hover-border: color-mix(in oklch, #C4C4C4 6%, #E6E5E2);
  --card-shadow:
      0 1px 2px rgba(0, 0, 0, 0.035),
      0 3px 8px rgba(0, 0, 0, 0.035),
      0 8px 28px rgba(0, 0, 0, 0.045);
  --card-hover-shadow:
      0 1px 2px rgba(0, 0, 0, 0.04),
      0 3px 10px rgba(0, 0, 0, 0.04),
      0 8px 28px rgba(0, 0, 0, 0.05),
      0 10px 40px 4px color-mix(in oklch, #C4C4C4 7%, transparent);

  /* --- the two curves, ola.css. One everyday move, one that overshoots. --- */
  --ease:   cubic-bezier(0.22, 1, 0.36, 1);
  --spring: cubic-bezier(0.34, 3.85, 0.64, 1);
}

@media (max-width: 700px) {
  :root {
    --field:   16.5px;   /* never below 16: iOS zooms the page on focus */
    --field-h: 56px;
    --gutter:  26px;
  }
}
@media (max-width: 360px) { :root { --gutter: 20px; } }

/* ===========================================================================
   2. THE FAMILY
   One variable font for the whole page, self-hosted, no network request to
   anyone. Roles are separated by the opsz axis rather than by a second face.
   ola.css @font-face, and the metric-matched local fallback with it, so a slow
   network shows Arial at Inter's metrics and the swap shifts nothing.
   =========================================================================== */

@font-face {
  font-family: "InterVariable";
  src: url("./assets/fonts/inter-subset.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Segoe UI"), local("Roboto");
  size-adjust: 105.3%;
  ascent-override: 92.0%;
  descent-override: 22.9%;
  line-gap-override: 0%;
}

/* ===========================================================================
   3. THE ROOM
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 96px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  min-height: 100svh;
  background: var(--ground);
  color: var(--ink);
  font: 400 var(--field)/1.55 var(--sans);
  font-variation-settings: "opsz" 14;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, canvas { display: block; max-width: 100%; }
img { height: auto; }

a { color: inherit; }

.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* One focus ring for the whole page, and it is never removed — only moved onto
   the object that actually reads as focused. ola.css. */
:where(a, button, input, summary):focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
  border-radius: 6px;
}
/* currentColor is white on the dark button and on the header pill, and a white
   ring on this ground is no ring at all. Those two take the ink instead, and
   flip back to the light ink wherever the ground under them is deep. */
.btn:focus-visible, .pill:focus-visible, .demo-toggle:focus-visible { outline-color: var(--ink); }
.on-deep .btn:focus-visible,
.on-deep-frame .pill:focus-visible { outline-color: var(--ink-on-deep); }

/* tryola.ai's selection: the ink itself, not the browser's blue */
::selection { background: rgba(20, 21, 25, 0.90); color: var(--ground); }

/* skip link */
.skip {
  position: absolute; top: 8px; left: 50%; z-index: 40;
  transform: translate(-50%, -200%);
  padding: 10px 18px; border-radius: var(--radius);
  background: var(--ink); color: var(--ground);
  font-size: var(--micro); font-weight: 500; text-decoration: none;
  transition: transform .28s var(--ease);
}
.skip:focus-visible { transform: translate(-50%, 0); outline-color: var(--ink); }

/* ===========================================================================
   4. THE FRAME (fixed header)
   The glass capsule is ola.css .frame, verbatim in structure and shadow.
   The blur sits on the capsule itself here rather than on a separate layer,
   because the capsule IS the background; the split-layer trick from x.ai is
   used instead on the full-width rail behind it, so the rail can fade in on
   scroll without touching the capsule's own contents.
   =========================================================================== */

.frame {
  position: fixed;
  z-index: 30;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 14px;
  height: var(--header-h);
  max-width: calc(100vw - 2 * var(--gutter));
  padding: 0 8px 0 22px;
  border-radius: var(--radius);
  background:
    linear-gradient(-75deg,
      rgba(255, 255, 255, 0.10),
      rgba(255, 255, 255, 0.42) 48%,
      rgba(255, 255, 255, 0.10));
  backdrop-filter: blur(22px) saturate(165%);
  -webkit-backdrop-filter: blur(22px) saturate(165%);
  box-shadow:
    inset 0 1px 1px var(--inner-light),
    inset 0 -1px 1px var(--shadow-soft),
    0 1px 3px var(--shadow-soft),
    0 10px 26px -8px var(--shadow);
  transition: transform .5s var(--ease), opacity .4s var(--ease), padding .58s var(--ease);
}

.frame-rule { width: 1px; height: 20px; background: var(--hairline); flex: 0 0 auto; }

.frame-nav {
  display: flex;
  align-items: center;
  gap: 4px;
}
.frame-nav a {
  padding: 6px 12px;
  border-radius: var(--radius);
  font-size: 14px;
  font-weight: 450;
  letter-spacing: -0.006em;
  color: var(--ink-body);
  text-decoration: none;
  white-space: nowrap;
  transition: color .2s var(--ease), background-color .2s var(--ease);
}
.frame-nav a:hover { color: var(--ink); background: rgba(0, 0, 0, 0.045); }

/* Below the ground's transition the page is black, and a black pill on black
   is a hole. Set from the same scroll position the shader would use. ola.css */
.on-deep-frame .frame {
  background:
    linear-gradient(-75deg,
      rgba(255, 255, 255, 0.05),
      rgba(255, 255, 255, 0.16) 48%,
      rgba(255, 255, 255, 0.05));
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.24),
    inset 0 -1px 1px rgba(0, 0, 0, 0.30),
    0 10px 30px -10px rgba(0, 0, 0, 0.55);
}
.on-deep-frame .wordmark { color: var(--ink-on-deep); }
.on-deep-frame .frame-rule { background: rgba(255, 255, 255, 0.20); }
.on-deep-frame .frame-nav a { color: var(--ink-on-deep-2); }
.on-deep-frame .frame-nav a:hover { color: #fff; background: rgba(255, 255, 255, 0.10); }

/* --- the wordmark and the way it collapses ---------------------------------
   ola.css, mechanism and geometry both, with our own word in it. Two things
   happen on one duration and one curve, and the second is the one that is easy
   to miss: the letters travel through a window whose LEFT edge is fixed, so
   " bruck" retracts INTO "jayden" rather than sliding off the end of the bar,
   and a negative end margin grows in lockstep to take back exactly the space
   they vacate, so the capsule closes up instead of keeping a hole.
   Nothing here touches opacity, because a fade is not a morph.
   --------------------------------------------------------------------------- */

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0;
  margin-inline-end: 0;
  flex: 0 0 auto;
  font-size: 19px;
  font-weight: 500;
  font-variation-settings: "opsz" 18;
  letter-spacing: -0.012em;
  color: var(--ink);
  text-decoration: none;
  line-height: 1;
  transition: margin-inline-end .58s var(--ease), color .3s var(--ease);
}
.wordmark-rest {
  flex: 0 0 auto;
  display: inline-block;
  overflow: hidden;
  width: 62px;
}
.wordmark-rest > span {
  display: inline-block;
  transform-origin: left center;
  transition: transform .58s var(--ease);
}
.wordmark.is-mark { margin-inline-end: -60px; }
.wordmark.is-mark .wordmark-rest > span { transform: translateX(-102%) scaleX(0.52); }

/* until the script has armed it, and whenever motion is refused, it holds the
   resting word and never plays */
.wordmark:not(.is-ready),
.wordmark:not(.is-ready) .wordmark-rest > span,
.wordmark.is-still,
.wordmark.is-still .wordmark-rest > span { transition: none; }
.wordmark.is-still { margin-inline-end: 0; }
.wordmark.is-still .wordmark-rest > span { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .wordmark, .wordmark-rest > span { transition: none; }
  .wordmark.is-mark { margin-inline-end: 0; }
  .wordmark.is-mark .wordmark-rest > span { transform: none; }
}

/* ===========================================================================
   5. BUTTONS
   poke.com's depth-button-v2, transcribed from the shipped markup. One
   component, two token sets. The recipe: a four-stop vertical gradient that
   holds flat for the first ~55-65% then falls away at the bottom, a three-tier
   ambient shadow, a 1.25px inset ring, an inset sheen, and a half-pixel
   text-shadow in the gradient's own direction so the label sits IN the
   surface. Hover moves brightness rather than swapping a colour, so the
   gradient survives it.
   The invisible 2.75rem hit-target expander is x.ai's, rendered only where the
   pointer is coarse.
   =========================================================================== */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 20px;
  border: 0;
  border-radius: 14px;
  font: 500 15px/1 var(--sans);
  font-variation-settings: "opsz" 16;
  letter-spacing: -0.008em;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform .15s ease-out, filter .15s ease-out;
}
.btn:active { transform: scale(0.98); }
.btn .tap {
  position: absolute; left: 50%; top: 50%;
  width: max(100%, 2.75rem); height: max(100%, 2.75rem);
  transform: translate(-50%, -50%);
}
@media (pointer: fine) { .btn .tap { display: none; } }

.btn-dark {
  color: #fff;
  text-shadow: 0 0.5px 0 rgba(0, 0, 0, 0.5);
  background: linear-gradient(180deg, #3A3A3A 0%, #3A3A3A 52.4%, #2C2C2C 80.29%, #1F1F1F 100%);
  box-shadow:
    0 0.5px 1px rgba(0, 0, 0, 0.08),
    0 1px 3px rgba(0, 0, 0, 0.1),
    0 4px 12px rgba(0, 0, 0, 0.08),
    inset 0 0 0 1.25px #353535,
    inset 0 0 12px 0 rgba(255, 255, 255, 0.1);
}
.btn-dark:hover { filter: brightness(1.2); }

.btn-light {
  color: #1C1C1C;
  text-shadow: 0 0.5px 0 #FFF;
  background: linear-gradient(180deg, #EDECEA 0%, #EDECEA 65%, #DCDCDC 85%, #C4C4C4 100%);
  box-shadow:
    0 0.5px 1px rgba(0, 0, 0, 0.04),
    0 1px 3px rgba(0, 0, 0, 0.06),
    0 4px 12px rgba(0, 0, 0, 0.04),
    inset 0 0 0 1.25px #C9C7C4,
    inset 0 0 12.2px 0 #FFF;
}
.btn-light:hover { filter: brightness(0.985); }

/* the small pill in the header: ola.css .pill, spring on the lift */
.pill {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 18px;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--ground);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.006em;
  text-decoration: none;
  white-space: nowrap;
  flex: 0 0 auto;
  box-shadow: 0 1px 2px rgba(24, 28, 38, 0.28);
  transition: transform .34s var(--spring), box-shadow .3s var(--ease);
}
.pill:hover { transform: translateY(-1px); box-shadow: 0 6px 16px -4px rgba(24, 28, 38, 0.34); }
.pill:active { transform: translateY(0) scale(0.97); }
.on-deep-frame .pill { background: var(--ink-on-deep); color: #101216; }

/* a text link that carries an arrow, anything.com's affordance */
.go-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.008em;
  color: var(--ink);
  text-decoration: none;
}
.go-link svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; transition: transform .34s var(--ease); }
.go-link:hover svg { transform: translateX(4px); }
.go-link u { text-decoration-thickness: 1px; text-underline-offset: 4px; text-decoration-color: var(--hairline-firm); }
.go-link:hover u { text-decoration-color: currentColor; }

/* ===========================================================================
   6. BANDS AND THEIR TYPE
   ola.css's own three: a heading, the one line under it, a quiet note. Flat
   ink, no gradient clip and nothing above the heading: the heading is the
   label.
   =========================================================================== */

main { position: relative; z-index: 1; }

.band {
  position: relative;
  padding: var(--band) var(--gutter);
}
.inner { width: 100%; max-width: var(--measure); margin-inline: auto; }
.inner-wide { width: 100%; max-width: var(--wide); margin-inline: auto; }

.say {
  margin: 0;
  font-size: var(--say);
  font-weight: 400;
  font-variation-settings: "opsz" 32;
  letter-spacing: -0.034em;
  line-height: 1.04;
  text-wrap: balance;
  color: var(--ink);
}
.h2 {
  margin: 0;
  font-size: var(--h2);
  font-weight: 400;
  font-variation-settings: "opsz" 32;
  letter-spacing: -0.034em;
  line-height: 1.02;
  text-wrap: balance;
  color: var(--ink);
}
.lede {
  margin: 0;
  max-width: 30em;
  font-size: var(--lede);
  line-height: 1.45;
  letter-spacing: -0.012em;
  color: var(--ink-body);
  text-wrap: pretty;
}
.h2 + .lede { margin-top: clamp(18px, 2.2vw, 28px); }
.note {
  margin: 0;
  font-size: var(--micro);
  line-height: 1.5;
  color: var(--ink-quiet);
}

/* ===========================================================================
   7. THE HERO
   The headline across the measure, then two short lines and two buttons
   beside the portrait. The aurora is Cluely's: stacked radial gradients and
   no image asset, here white light and a cool low shadow.
   =========================================================================== */

.hero {
  padding-top: clamp(124px, 18vh, 196px);
  padding-bottom: clamp(56px, 9vh, 112px);
  overflow: hidden;
}
.hero::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 150%;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(58% 46% at 50% 6%, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0) 62%),
    radial-gradient(120% 78% at 50% -8%, rgba(214, 219, 232, 0.55) 18%, rgba(214, 219, 232, 0) 72%),
    radial-gradient(90% 60% at 50% 108%, rgba(24, 28, 38, 0.055) 0%, rgba(24, 28, 38, 0) 70%);
}

/* The headline runs the full measure rather than sharing a column with the
   portrait, because line two has to hold "i build agents that browse" on one
   line while the carousel is running. */
.hero > .inner-wide > .hero-say { max-width: var(--measure); }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
  align-items: start;
  gap: clamp(40px, 6vw, 96px);
  margin-top: clamp(30px, 4.5vh, 52px);
}
.hero-lede { max-width: 30em; }

/* --- the two lines -------------------------------------------------------
   Each line is its own block, so the break is fixed and a long verb can widen
   a line but never add one. ola.css says the same thing about its own hero and
   for the same reason: the copy under it must not move under someone's thumb.
   ------------------------------------------------------------------------- */
/* THE HERO TAKES ITS OWN SIZE, solved once against the longest sentence it
   can ever hold — "i build agents that browse." — before anything moves.
   ola.css does the same thing for the same reason: a hero whose line is longer
   than its other lines needs a scale of its own, or it wraps. `--hero-fit` is
   1 wherever the line already fits, so nothing shrinks that does not have to. */
.hero-say { margin: 0; font-size: calc(var(--say) * var(--hero-fit, 1)); }

/* --- the ink moves with the page ----------------------------------------
   The headline is not one flat black for the whole scroll: it carries a very
   small amount of the body ink, and how much depends on how far the hero has
   travelled. At the top it is `--ink` exactly; a viewport later it has drifted
   about a quarter of the way toward `--ink-body`, which is roughly #141519 to
   #242730 — a shift you feel rather than see, and one that stays inside the
   two inks the page already uses. No third hue enters, and nothing sweeps:
   x.ai's restraint, moved from a bar under one word onto the ink itself.
   `--hero-t` is set from the same rAF-throttled scroll pass that drives the
   wordmark, so the page adds no second listener for it.
   ------------------------------------------------------------------------- */
.hero-say { color: var(--ink); }
@supports (color: color-mix(in oklab, red 50%, blue)) {
  .hero-say { color: color-mix(in oklab, var(--ink-body) calc(var(--hero-t, 0) * 26%), var(--ink)); }
}
.hero-vis { display: block; }
.hl { display: block; white-space: nowrap; }
.hl + .hl { margin-top: 0.02em; }

/* THE SWAP SLOT. It holds one phrase at a time in a box of a known width, so
   the full stop after it never moves while the verb underneath is changing,
   and so the collapse to "ola" is a real width closing rather than a reflow.
   Both widths are measured off the real rendered glyphs, never estimated from
   letter counts — letters set as inline-blocks are a few px wider than a plain
   text run. ola.css's `.vow`, one level up. */
.swap {
  /* an atomic inline box swallows the letter-spacing that would otherwise sit
     between the last letter of the word and the full stop after it */
  margin-right: -0.034em;
  display: inline-grid;
  position: relative;
  vertical-align: baseline;
  width: var(--swap-w, auto);
  transition: width .42s var(--ease);
}
.swap { justify-items: start; }
.swap > .phase { grid-area: 1 / 1; text-align: left; white-space: nowrap; }
/* the phrase on its way out must not size the slot: for the length of the
   transition the slot holds two, and the wider of them would push the line off
   the side of the screen. It is only a picture by then. */
.swap > .phase.is-out { position: absolute; top: 0; left: 0; }

/* THE WORD ROLLS THROUGH A WINDOW.
   The crop is Cluely's (`overflow-hidden` with a negative margin matched by an
   equal padding, so the word's own ascender and descender box is taken out of
   the flow and the slot still sits on the line's baseline). Without it a word
   arriving from below at this size landed on top of the paragraph underneath
   the headline.

   ⚠️ AND THE WINDOW NEEDS SOMETHING IN FLOW TO HOLD IT OPEN. The word on its
   way out has to leave the flow — while two words are in it the slot is as
   wide and as tall as the WIDER of them, which pushes the line around on every
   verb — so for the 140ms between one leaving and the next being appended the
   slot had no in-flow content at all and collapsed to its own padding: a
   measured 18px against a 74px headline. A hidden copy of the longest verb
   sits in it permanently and holds the box open and the baseline true; every
   word a reader actually sees is positioned over it.
   ------------------------------------------------------------------------- */
/* ⚠️ THE CROP CANNOT GO ON THE SLOT ITSELF. An inline-block whose overflow is
   not `visible` takes its baseline from its bottom margin edge instead of from
   its last line box, so putting the crop here lifted every verb off the line
   it was supposed to be sitting on. And a block with non-visible overflow has
   no baseline to give its parent either, which is the same failure one level
   down. The hidden copy stays in the flow and is the only thing that decides
   the slot's size and its baseline; the window is lifted out of the flow
   entirely and simply covers it.

   THE SLOT IS HELD AT THE WIDEST VERB and never moves after that. Gliding it
   per word was smoother in isolation and wrong in place: it made the length of
   line two a function of which verb happened to be showing, which is exactly
   the thing a headline sitting above a paragraph must not do. */
.vow {
  display: inline-block;
  position: relative;
  vertical-align: baseline;
  width: var(--vow-w, auto);
}
.vow .ghost { display: block; visibility: hidden; white-space: nowrap; }
.vow .win {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  bottom: -0.14em;        /* room for a descender: "buy" has one */
  overflow: hidden;
}
.vow .letters { position: absolute; left: 0; top: 0; white-space: nowrap; }

/* The carousel runs faster than the page's ordinary letter motion, and its
   words travel further: at 14px the outgoing and incoming words sat on top of
   each other at half opacity each and read as a double exposure. The travel is
   set in em so it stays proportional to the headline at every size. */
.vow .ltr {
  transition:
    transform .11s var(--ease) var(--d, 0ms),
    opacity   .10s var(--ease) var(--d, 0ms),
    filter    .10s var(--ease) var(--d, 0ms);
}
.vow .letters.is-in .ltr  { transform: translateY(0.62em); }
.vow .letters.is-out .ltr { transform: translateY(-0.62em); }

@media (prefers-reduced-motion: reduce) {
  .vow .ltr { transition: opacity .14s var(--ease); transition-delay: 0ms; }
  .vow .letters.is-in .ltr,
  .vow .letters.is-out .ltr { transform: none; }
}
.no-blur .vow .letters.is-in .ltr,
.no-blur .vow .letters.is-out .ltr { filter: none; }

/* measured off-screen, from the real fonts, before anything moves */
.ruler {
  position: absolute;
  visibility: hidden;
  white-space: nowrap;
  pointer-events: none;
  top: 0; left: 0;
}

@media (prefers-reduced-motion: reduce) {
  .swap { transition: none; }
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 32px;
}

/* --- the portrait ---------------------------------------------------------
   Held in the same glass the field and the capsule are made of, so the one
   photograph on the page belongs to the same material as everything around it.
   --------------------------------------------------------------------------- */

.portrait {
  position: relative;
  margin: 0;
  justify-self: end;
  width: 100%;
  max-width: 380px;
}
.portrait-frame {
  position: relative;
  border-radius: 26px;
  overflow: hidden;
  background: var(--ground-deep);
  box-shadow: var(--ladder-low), 0 0 0 1px var(--glass-edge);
}
.portrait-frame img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 24%;
  transform: scale(1.02);
}
/* an inner hairline, drawn over the image so the frame reads as an edge rather
   than as the photograph simply stopping */
.portrait-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.34), inset 0 -60px 80px -60px rgba(20, 21, 25, 0.35);
}

/* ===========================================================================
   8. THE SWEEP UNDER ONE WORD
   x.ai paints a 3px bar under the single word its whole message hangs on and
   sweeps a gradient across it once, 400% background-size, background-position
   travelling 150% -> -150%. Theirs is a nine-stop rainbow; this page has no
   accent colour, so the sweep is light travelling along an ink bar. Same
   mechanism, one pass, then it rests.
   =========================================================================== */

.marked { position: relative; display: inline-block; white-space: nowrap; }
.marked .bar {
  position: absolute;
  left: 0; right: 0; bottom: -0.06em;
  height: 3px;
  border-radius: 2px;
  transform-origin: left;
  transform: scaleX(0);
  opacity: 0;
  background-image: linear-gradient(90deg,
    rgba(20, 21, 25, 0.30) 0%,
    rgba(20, 21, 25, 0.30) 35%,
    rgba(20, 21, 25, 0.85) 47%,
    rgba(255, 255, 255, 0.95) 52%,
    rgba(20, 21, 25, 0.85) 57%,
    rgba(20, 21, 25, 0.30) 68%,
    rgba(20, 21, 25, 0.30) 100%);
  background-size: 400% 100%;
}
.marked.is-drawn .bar {
  opacity: 1;
  transform: scaleX(1);
  transition: transform .62s var(--ease), opacity .3s var(--ease);
  animation: sweep 2600ms linear 1 340ms;
}
@keyframes sweep {
  0%   { background-position: 150% 0; }
  100% { background-position: -150% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .marked.is-drawn .bar { transition: none; animation: none; background-position: 50% 0; }
}

/* ===========================================================================
   9. LETTERS
   ola/assets/letters.css, verbatim. A short 14px of travel, a fade, and a blur
   of 4px on a 14ms stagger between neighbours. The blur is the part that
   matters: a clipped edge reads as CUT OFF, a blur reads as GONE. Safari drops
   the blur only (.no-blur), set from script.
   =========================================================================== */

.wd { display: inline-block; white-space: nowrap; }
.ltr {
  display: inline-block;
  transform: translateY(0);
  opacity: 1;
  filter: blur(0px);
  transition:
    transform .26s var(--ease) var(--d, 0ms),
    opacity   .22s var(--ease) var(--d, 0ms),
    filter    .22s var(--ease) var(--d, 0ms);
}
.letters.is-in .ltr {
  transform: translateY(14px);
  opacity: 0;
  filter: blur(4px);
  transition: none;
}
/* And away upward, losing focus rather than sliding behind an edge. This is
   the half of letters.js the first pass of this page had no use for — nothing
   here left, it only ever arrived — so it was never ported, and the carousel
   then had an exit state that changed nothing: measured off a live run, every
   outgoing word sat at opacity 1.00 and its full travel at once, which is what
   put two readable words on the line together. */
.letters.is-out .ltr {
  transform: translateY(-14px);
  opacity: 0;
  filter: blur(4px);
}
.no-blur .ltr,
.no-blur .letters.is-in .ltr,
.no-blur .letters.is-out .ltr { filter: none; }

@media (prefers-reduced-motion: reduce) {
  .ltr { transform: none; filter: none; transition: opacity .18s var(--ease); transition-delay: 0ms; }
  .letters.is-in .ltr { transform: none; opacity: 0; filter: none; transition: none; }
  .letters.is-out .ltr {
    transform: none; opacity: 0; filter: none;
    transition: opacity .12s var(--ease); transition-delay: 0ms;
  }
}

/* --- the reveal, ola.css. Fires once: a page you cannot re-scroll into
       hiding. Per-element stagger is authored in the HTML as data-delay.
       Hidden only under .js, which a one-line script in the head sets: with
       no script nothing would ever reveal it, and the page would be a
       headline over an empty ground. --- */
.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity   .66s var(--ease) var(--reveal-delay, 0ms),
    transform .82s var(--ease) var(--reveal-delay, 0ms);
}
.js .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { transform: none; transition: opacity .28s var(--ease) var(--reveal-delay, 0ms); }
}

/* ===========================================================================
   10. OLA
   Four screens. Ola herself, large, with the one line that says what she is.
   The two rails of what she does. The ask in Ola's own dark capsule beside a
   phone built the way tryola.ai builds its phones, playing the real
   recording. Last the vision, one statement in two inks.
   =========================================================================== */

.ola-hero {
  display: grid;
  justify-items: center;
  text-align: center;
}
.ola-hero .lede { margin: clamp(18px, 2.2vw, 28px) auto 0; max-width: 30em; }

/* Her stage is the width of the page and as tall as she needs: the room in
   the middle is the 64 unit box of the mark, and everything round it is
   where her play may take her (a card she blooms beside her, a little one in
   orbit, a drop thrown across). tryola.ai's ola-play.js reads the stage as
   her field. The canvas reaches above it, so a hop has air to go into. */
.ola-stage {
  --stage-h: clamp(300px, 37vw, 520px);
  position: relative;
  width: 100%;
  height: var(--stage-h);
  margin: calc(var(--band) * -0.42) auto calc(clamp(28px, 4vw, 56px) * -1);
  /* a double click on her is hers, not a word selected under her */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
.ola-room {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--stage-h) * 0.62);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  color: var(--ink);
}
.ola-still {
  width: 100%;
  height: 100%;
  transition: opacity .5s var(--ease);
}
.ola-canvas {
  position: absolute;
  inset: -34% 0 0 0;
  width: 100%;
  height: 134%;
  pointer-events: none;
}
.ola-stage.is-live .ola-still { opacity: 0; }
.ola-stage.is-live .ola-room { cursor: pointer; }

/* --- what she does --------------------------------------------------------
   Two rails running against each other. Cluely's logo strip mechanism
   (cluely.com/_next/static/css/e0f47fde64bf82ef.css):

       @keyframes logos { 0% { transform: translate(0) } to { transform: translate(-50%) } }

   Each pill is Poke's card: a three tier ambient shadow at rest, a hover that
   adds a fourth glow layer, and the 6px lift on 200ms ease-out. The rails
   stop under a pointer, so a pill can be read rather than chased.
   ------------------------------------------------------------------------- */

.does {
  /* full bleed out of the band's gutters: a strip that stops at the text
     column reads as a component, and this is a current running past */
  margin-inline: calc(var(--gutter) * -1);
  display: flex;
  flex-direction: column;
  gap: 14px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12%, #000 88%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 12%, #000 88%, transparent 100%);
}
.does { margin-top: clamp(56px, 9vh, 104px); }

.rail { display: flex; overflow: hidden; }
.rail .track { display: flex; flex: 0 0 auto; }
.rail .set {
  display: flex;
  flex: 0 0 auto;
  gap: 14px;
  margin: 0;
  padding: 8px 7px;          /* room for the lift, so a raised pill is not clipped */
  list-style: none;
}

/* armed only once the script has cloned enough copies to fill the width */
.is-running .rail .track { will-change: transform; animation: rail-left var(--dur, 42s) linear infinite; }
.is-running [data-rail="b"] .track { animation-name: rail-right; }
.is-running:hover .rail .track,
.is-running:focus-within .rail .track,
.is-running.is-off .rail .track { animation-play-state: paused; }

@keyframes rail-left  { 0% { transform: translateX(0) }    to { transform: translateX(-50%) } }
@keyframes rail-right { 0% { transform: translateX(-50%) } to { transform: translateX(0) } }

.cap {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  height: 52px;
  padding: 0 22px;
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--card-shadow);
  font-size: 16px;
  letter-spacing: -0.010em;
  color: var(--ink);
  white-space: nowrap;
  user-select: none;
  transition:
    transform 200ms ease-out,
    box-shadow 250ms cubic-bezier(.25, .46, .45, .94),
    border-color 250ms cubic-bezier(.25, .46, .45, .94);
}
.cap:hover {
  transform: translateY(-6px);
  border-color: var(--card-hover-border);
  box-shadow: var(--card-hover-shadow);
}

/* Standing still, the same ten pills sit in centred rows. A finished layout,
   not a stripped one, which is why the animation is armed from script. */
.does:not(.is-running):not(.is-lining) { margin-inline: 0; -webkit-mask-image: none; mask-image: none; }
.does:not(.is-running):not(.is-lining) .rail { overflow: visible; }
.does:not(.is-running):not(.is-lining) .rail .set { flex-wrap: wrap; justify-content: center; width: 100%; }
/* the second rail says the same ten in another order; standing still it
   would only say everything twice */
.does:not(.is-running):not(.is-lining) [data-rail="b"] { display: none; }
.is-lining .rail { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .is-running .rail .track { animation: none; }
  .cap:hover { transform: none; }
}

/* --- the recording ------------------------------------------------------- */

/* words and phone travel as one centred pair, so the gap between them is a
   measure and not whatever the column happens to leave over */
.ola-intro {
  display: grid;
  grid-template-columns: minmax(0, 27rem) auto;
  justify-content: center;
  align-items: center;
  gap: clamp(48px, 8vw, 128px);
  margin-top: calc(var(--band) * 0.95);
}

/* the asks, in tryola.ai's capsule: ink ground, ground ink, a pill. Two of
   them, the second a step in, the way a second message sits under a first */
.asks {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}
.ask {
  display: inline-flex;
  align-items: center;
  min-height: 50px;
  margin: 0;
  padding: 13px 24px;
  border-radius: 26px;
  background: var(--ink);
  color: var(--ground);
  font-size: 16px;
  line-height: 1.4;
  letter-spacing: -0.008em;
  box-shadow: 0 1px 2px rgba(24, 28, 38, 0.24), 0 12px 28px -12px rgba(24, 28, 38, 0.5);
}
.ask + .ask { margin-left: clamp(18px, 2.4vw, 32px); }
.ola-words .lede { margin-top: clamp(24px, 3vw, 34px); max-width: 21em; }

/* --- the phone ----------------------------------------------------------
   home.css .phone, .phone-body and .phone-screen, with the recording as the
   screen: a brushed band, a hairline of black, the glass. Every measure is
   in cqw, so the whole device scales as one object. The body takes its
   height from the video's own aspect ratio, so the poster giving way to the
   first frame moves nothing. */
.phone {
  container-type: inline-size;
  width: clamp(250px, 22vw, 316px);
  margin: 0;
}
.phone-body {
  position: relative;
  padding: 1.214cqw;
  border-radius: 14.56cqw;
  background: linear-gradient(145deg, #D9DADE 0%, #A5A8AF 22%, #ECEDEF 48%, #8D9098 76%, #C9CBD0 100%);
  box-shadow:
    inset 0 0 0 0.35cqw rgba(255, 255, 255, 0.35),
    0 0.6cqw 1.2cqw rgba(12, 13, 16, 0.10),
    0 6cqw 9cqw -2cqw rgba(12, 13, 16, 0.22),
    0 16cqw 22cqw -8cqw rgba(12, 13, 16, 0.20);
}
.phone-body::before {   /* the black between the band and the glass */
  content: "";
  position: absolute;
  inset: 0.55cqw;
  border-radius: 14cqw;
  background: #08090B;
}
.phone-body video {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 720 / 1558;
  border-radius: 13.35cqw;
  background: #F4F4F2;
  object-fit: cover;
}
.phone figcaption {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 20px;
  font-size: var(--micro);
  line-height: 1.4;
  color: var(--ink-quiet);
}

/* one control, a small ring of glass beside the caption, not over the
   recording, where it would sit on the app's own buttons */
.demo-toggle {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.75);
  box-shadow: inset 0 0 0 1px var(--hairline-firm), 0 1px 2px rgba(24, 28, 38, 0.06);
  color: var(--ink);
  cursor: pointer;
  transition: transform .34s var(--spring), box-shadow .2s var(--ease), background-color .2s var(--ease);
}
.demo-toggle[hidden] { display: none; }
.demo-toggle:hover { background: #fff; box-shadow: inset 0 0 0 1px var(--glass-edge-lit), 0 4px 12px -4px rgba(24, 28, 38, 0.18); }
.demo-toggle:active { transform: scale(0.94); }
.demo-toggle svg { width: 13px; height: 13px; }
.demo-toggle .i-pause { fill: none; stroke: currentColor; stroke-width: 2.8; stroke-linecap: round; }
.demo-toggle .i-play { fill: currentColor; display: none; }
.demo-toggle.is-paused .i-pause { display: none; }
.demo-toggle.is-paused .i-play { display: block; }
.demo-toggle:focus-visible { border-radius: 50%; }

/* --- the vision -----------------------------------------------------------
   His words, the size of a statement and the width of a reading line. */
.vision {
  margin-top: calc(var(--band) * 1.15);
  text-align: center;
}
.vision blockquote { margin: 0 auto; max-width: 22em; font-size: var(--vision); }
.vision blockquote p {
  margin: 0;
  font-size: 1em;
  font-weight: 400;
  font-variation-settings: "opsz" 30;
  letter-spacing: -0.026em;
  line-height: 1.2;
  color: var(--ink-body);
  text-wrap: balance;
}
.vision .said { color: var(--ink); }
.vision-after { margin: clamp(30px, 4vw, 44px) 0 0; }

/* ===========================================================================
   11. TRACK RECORD
   The deck's founder slide, made a page: every result a card, the real logo
   on a tile in the logo's own colour, the date, what happened, one line under
   it where one is needed. The two photographs live in the two biggest
   results. The cards rise in a stagger as they arrive and lift under a
   pointer with a glow mixed from their own colour.
   =========================================================================== */

/* the logo tiles, shared by the run and the cards */
.tile {
  display: grid;
  place-items: center;
  overflow: hidden;
  color: var(--ink);
}
.tile img { width: auto; height: auto; }
.wm {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 19px;
  font-weight: 650;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.wm svg { width: 1.25em; height: 1.25em; flex: 0 0 auto; fill: currentColor; }
.mask-logo {
  display: block;
  height: 21px;
  aspect-ratio: var(--ar, 7);
  background: #E2001A;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.t-launch       { background: #0F1524; }
.t-launch-light { background: #fff; box-shadow: inset 0 0 0 1px var(--hairline); }
.t-oasis        { background: linear-gradient(135deg, #1E1452, #5A47E0); color: #fff; }
.t-raisi        { background: #F1F1F3; color: #0B0B0C; }
.t-raisi .wm    { font-size: 25px; font-weight: 750; letter-spacing: -0.05em; }
.t-claude       { background: #C96442; color: #FBF3EA; }
.t-claude .wm   { font-family: Georgia, "Times New Roman", serif; font-weight: 400; letter-spacing: -0.01em; }
.wm-stack       { gap: 11px; line-height: 1.02; text-align: left; white-space: normal; }
.wm-stack svg   { width: 1.6em; height: 1.6em; }
.t-idealab      { background: linear-gradient(135deg, #0F1F3D 0%, #24186E 70%, #3A23A6 100%); }
.t-ola          { background: #141519; color: #F7F6F4; }
.t-ola-light    { background: #fff; color: #141519; box-shadow: inset 0 0 0 1px var(--hairline); }
.t-cursor       { background: #EDECEA; }
.t-deka         { background: #fff; box-shadow: inset 0 0 0 1px var(--hairline); }
.t-wealth       { background: #F1F1F3; color: #141519; }
.t-dekabank     { background: #fff; box-shadow: inset 0 0 0 1px var(--hairline); }
.tile .mark     { width: 46px; height: 46px; }

/* --- the cards ------------------------------------------------------------- */
.cards {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* Strictly in the order of the list, newest first, at every width: no
     dense packing and no row spans, which pull later results up into gaps.
     The spans are chosen so each row fills exactly (four across: LAUNCH 2+1+1,
     then 1+1+2 with WHU, then 1+1+1+1, then 1+1+2 with the aside). */
  gap: 16px;
  margin: clamp(34px, 5vh, 54px) 0 0;
  padding: 0;
  list-style: none;
}
.card {
  --d: 0ms;
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 9px;
  border: 1px solid var(--card-border);
  border-radius: 24px;
  background: #fff;
  box-shadow: var(--card-shadow);
  transition:
    transform 200ms ease-out,
    box-shadow 250ms cubic-bezier(.25, .46, .45, .94),
    border-color 250ms cubic-bezier(.25, .46, .45, .94);
}
.card:hover {
  transform: translateY(-6px);
  border-color: color-mix(in oklch, var(--brand, #C4C4C4) 18%, #E6E5E2);
  box-shadow:
    var(--card-hover-shadow),
    0 22px 46px -22px color-mix(in oklch, var(--brand, #C4C4C4) 60%, transparent);
}
.card .tile {
  height: 92px;
  border-radius: 16px;
  transition: transform .5s var(--ease);
}
.card:hover .tile { transform: scale(1.015); }
.card .tile img { max-width: 76%; max-height: 36px; }
.card .t-idealab img { max-height: 44px; }

.card-body {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 16px 9px 9px;
}
.card-body time {
  font-size: 12.5px;
  letter-spacing: 0.01em;
  font-feature-settings: "tnum" 1;
  color: var(--ink-quiet);
}
.card-t {
  margin: 0;
  font-size: 17px;
  font-weight: 500;
  font-variation-settings: "opsz" 18;
  letter-spacing: -0.016em;
  line-height: 1.3;
  color: var(--ink);
  text-wrap: pretty;
}
.card-t a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  text-decoration-color: var(--hairline-firm);
  transition: text-decoration-color .2s var(--ease);
}
.card-t a:hover { text-decoration-color: currentColor; }
.card-d {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  letter-spacing: -0.004em;
  color: var(--ink-body);
  text-wrap: pretty;
}

/* the results that have photographs. The two biggest take two columns and
   two rows and cross fade slowly through theirs; the others stand two rows
   tall with one portrait each. */
.card-big { grid-column: span 2; }
/* a result with no photograph shares its row with ones that have one: its
   logo tile takes up the height, so the card is as tall as its neighbours */
.card:not(.card-big):not(.card-tall):not(.card-aside) .tile { flex: 1 1 auto; height: auto; min-height: 92px; }
.card-photo {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: 16px;
  overflow: hidden;
  background: var(--ground-deep);
}
.card-big .card-photo { aspect-ratio: 3 / 2; }
.card-photo picture { position: absolute; inset: 0; }
.card-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1s var(--ease);
}
.card:hover .card-photo img { transform: scale(1.03); }
/* the stack: only the photograph that is on shows. With no script the first
   one is simply there. */
.card-photo[data-stack] picture {
  opacity: 0;
  transition: opacity 1.1s var(--ease);
}
.card-photo[data-stack] picture:first-of-type { opacity: 1; }
.card-photo[data-stack].is-armed picture:first-of-type { opacity: 0; }
.card-photo[data-stack].is-armed picture.is-on { opacity: 1; }
/* a slow drift on the one that is showing, so the stack is never quite still */
.card-photo[data-stack].is-armed picture img { transition: transform 7s linear; }
.card-photo[data-stack].is-armed picture.is-on img { transform: scale(1.06); }
.stack-dots {
  position: absolute;
  left: 12px;
  bottom: 11px;
  display: none;
  gap: 5px;
}
.is-armed .stack-dots { display: flex; }
.stack-dots i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.5);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  transition: background-color .4s var(--ease), width .4s var(--ease);
}
.stack-dots i.is-on { width: 16px; border-radius: 3px; background: #fff; }
.card-photo .credit {
  position: absolute;
  right: 10px;
  bottom: 8px;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.86);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.card-big .tile, .card-tall .tile { height: 60px; margin-top: 9px; }
.card-big .tile img, .card-tall .tile img { max-height: 28px; }
.card-big .t-idealab img { max-height: 34px; }

/* the line that is not a result */
.card-aside {
  grid-column: span 2;
  justify-content: center;
  gap: 6px;
  padding: 26px 28px;
  border-style: dashed;
  border-color: var(--hairline-firm);
  background: transparent;
  box-shadow: none;
}
.card-aside:hover { transform: none; box-shadow: none; border-color: var(--hairline-firm); }
.aside-t {
  margin: 0;
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.018em;
  line-height: 1.35;
  color: var(--ink);
  text-wrap: balance;
}

/* the stagger. Hidden only under .js, so with no script every card is
   simply there. Each batch that arrives together rises in reading order. */
.js .cards .card {
  opacity: 0;
  transform: translateY(26px) scale(0.985);
  transition:
    opacity .7s var(--ease) var(--d),
    transform .9s var(--ease) var(--d),
    box-shadow 250ms cubic-bezier(.25, .46, .45, .94),
    border-color 250ms cubic-bezier(.25, .46, .45, .94);
}
.js .cards .card.in { opacity: 1; transform: none; }
/* once it has landed it takes the card's own quick hover again */
.js .cards .card.in.settled {
  transition:
    transform 200ms ease-out,
    box-shadow 250ms cubic-bezier(.25, .46, .45, .94),
    border-color 250ms cubic-bezier(.25, .46, .45, .94);
}
.js .cards .card.in.settled:hover { transform: translateY(-6px); }
.js .cards .card-aside.in.settled:hover { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js .cards .card { transform: none; transition: opacity .3s var(--ease) var(--d); }
  .card:hover, .js .cards .card.in.settled:hover { transform: none; }
  .card:hover .tile, .card:hover .card-photo img { transform: none; }
  .card-photo[data-stack].is-armed picture.is-on img { transform: none; }
}

/* ===========================================================================
   12. HOW I BUILD, AND THE OPEN SOURCE
   One sentence for the numbers, then the two repositories as cards. Each
   opens on a small animation of what it does: lanes of agents running at
   once, and speech turning into a written sentence. Then the path on GitHub,
   the name, one line from its README and the language.
   =========================================================================== */

.oss { margin-top: clamp(64px, 9vh, 112px); scroll-margin-top: 110px; }
.oss-h {
  margin: 0 0 20px;
  font-size: clamp(20px, 1.8vw, 24px);
  font-weight: 500;
  font-variation-settings: "opsz" 22;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.repo-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.repo-cards li { display: flex; }
.repo {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 9px;
  border: 1px solid var(--card-border);
  border-radius: 24px;
  background: #fff;
  box-shadow: var(--card-shadow);
  color: inherit;
  text-decoration: none;
  transition:
    transform 200ms ease-out,
    box-shadow 250ms cubic-bezier(.25, .46, .45, .94),
    border-color 250ms cubic-bezier(.25, .46, .45, .94);
}
.repo:hover {
  transform: translateY(-6px);
  border-color: var(--card-hover-border);
  box-shadow: var(--card-hover-shadow), 0 22px 46px -24px color-mix(in oklch, var(--lang) 55%, transparent);
}
.repo:focus-visible { border-radius: 24px; outline-offset: 4px; }

/* --- what each project does, small ---------------------------------------- */
.demo {
  position: relative;
  display: block;
  height: 196px;
  border-radius: 16px;
  overflow: hidden;
}

/* Lanes Harness, as it is: the head agent's terminal launching lanes, and the
   `lane list` table under it following their states. Light, monospace, calm,
   like the Prompt Whisper card beside it. */
.demo-lanes {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 16px 18px 14px;
  background: linear-gradient(180deg, #FBFAF7 0%, #F1EFEA 100%);
  box-shadow: inset 0 0 0 1px var(--hairline);
  color: var(--ink);
  font: 12px/1.5 ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", Menlo, Consolas, monospace;
}
.ln-head, .ln-out { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ln-p { color: #8B8F98; }
.ln-caret {
  display: inline-block;
  width: 0.55em;
  height: 1.1em;
  margin-left: 2px;
  vertical-align: -0.2em;
  background: var(--ink);
  opacity: 0.75;
}
.is-live .ln-caret { animation: ln-blink 1.06s steps(1) infinite; }
@keyframes ln-blink { 50% { opacity: 0; } }
.ln-out { min-height: 1.5em; font-size: 11.5px; color: #A1640F; }
.ln-table {
  display: grid;
  gap: 2px;
  margin-top: 8px;
  padding-top: 7px;
  border-top: 1px solid var(--hairline-firm);
}
.ln-row {
  --c: #8B8F98;
  display: grid;
  grid-template-columns: 34px 88px minmax(0, 1fr) 34px;
  align-items: center;
  gap: 10px;
  height: 25px;
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.ln-th { height: 18px; font-size: 11px; color: #8B8F98; }
.ln-row[data-off] { opacity: 0; transform: translateY(3px); }
.ln-kind { display: inline-flex; align-items: center; gap: 6px; color: #5C606A; }
.ln-kind img { width: 14px; height: 14px; }
.ln-st {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 1px 9px 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  color: var(--c);
  background: color-mix(in oklch, var(--c) 13%, transparent);
  transition: color .4s var(--ease), background-color .4s var(--ease);
}
.ln-st::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.ln-q { justify-self: end; color: #8B8F98; font-variant-numeric: tabular-nums; }
.ln-row[data-state="starting"]    { --c: #8B8F98; }
.ln-row[data-state="running"]     { --c: #2F6FDB; }
.ln-row[data-state="needs-input"] { --c: #A1640F; }
.ln-row[data-state="finished"]    { --c: #1F8A5B; }
.is-live .ln-row[data-state="running"] .ln-st::before { animation: ln-pulse 1.4s ease-in-out infinite; }
@keyframes ln-pulse { 50% { opacity: 0.25; } }

/* the chip above both animations */
.demo-chip {
  position: absolute;
  left: 50%;
  top: 14px;
  padding: 5px 12px 6px;
  border-radius: 999px;
  background: #0F5132;
  color: #fff;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: -0.005em;
  white-space: nowrap;
  transform: translateX(-50%);
  transition: opacity .3s var(--ease), transform .5s var(--spring);
}
.demo-chip.is-out { opacity: 0; transform: translate(-50%, 6px) scale(0.94); }

/* Prompt Whisper, after Wispr Flow's hero: what you say runs along a curve
   into the waveform pill and comes out as the written sentence. */
.demo-whisper {
  background: linear-gradient(180deg, #FBFAF7 0%, #F1EFEA 100%);
  box-shadow: inset 0 0 0 1px var(--hairline);
}
.demo-whisper svg {
  display: block;
  width: 100%;
  height: 100%;
  /* the ribbons come from nowhere and go nowhere, as on Wispr Flow's own page */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 16%, #000 84%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 16%, #000 84%, transparent 100%);
}
.wh-said { font: italic 400 14px var(--sans); fill: #9A9DA5; letter-spacing: -0.01em; }
.wh-ribbon { fill: none; stroke: #141519; stroke-width: 30; stroke-linecap: round; }
.wh-clean { font: 500 13.5px var(--sans); fill: #F7F6F4; letter-spacing: -0.01em; }
.wh-pill > rect { fill: #fff; stroke: #141519; stroke-width: 2.2; }
.wh-wave rect { fill: #141519; transform-box: fill-box; transform-origin: center; }
.is-live .wh-wave rect { animation: wh-bar 0.8s ease-in-out infinite alternate; }
.is-live .wh-wave rect:nth-child(2n) { animation-duration: 0.62s; }
.is-live .wh-wave rect:nth-child(3n) { animation-duration: 0.95s; animation-delay: -0.3s; }
.is-live .wh-wave rect:nth-child(4n) { animation-delay: -0.5s; }
@keyframes wh-bar { from { transform: scaleY(0.3); } to { transform: scaleY(1); } }

@media (prefers-reduced-motion: reduce) {
  .is-live .ln-caret, .is-live .ln-row .ln-st::before, .is-live .wh-wave rect { animation: none; }
}

.repo-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 7px;
  padding: 20px 15px 12px;
}
.repo-path {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-quiet);
}
.repo-path svg { width: 16px; height: 16px; fill: var(--ink); }
.repo-name {
  font-size: 22px;
  font-weight: 500;
  font-variation-settings: "opsz" 22;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.repo-text {
  font-size: 15.5px;
  line-height: 1.5;
  letter-spacing: -0.008em;
  color: var(--ink-body);
  text-wrap: pretty;
}
.repo-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
  padding-top: 16px;
  font-size: 13.5px;
  color: var(--ink-quiet);
}
.lang { display: inline-flex; align-items: center; gap: 8px; }
.lang i { width: 10px; height: 10px; border-radius: 50%; background: var(--lang); }
.repo-go { display: inline-flex; align-items: center; gap: 6px; color: var(--ink); font-weight: 500; }
.repo-go svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform .34s var(--ease);
}
.repo:hover .repo-go svg { transform: translate(2px, -2px); }
@media (prefers-reduced-motion: reduce) { .repo:hover { transform: none; } }

/* ===========================================================================
   12b. WHAT PEOPLE ASK ME
   Four questions and their answers, in plain words: who I am, what Ola is,
   who founded it, and how it differs. A question is set like the open source
   heading, an answer like body text, two to a row on a wide screen and one
   under the other on a phone. Nothing new: the tokens, sizes and ink are the
   page's own.
   =========================================================================== */

.faq {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(36px, 5vh, 56px) clamp(28px, 4vw, 64px);
  margin-top: clamp(40px, 6vh, 72px);
}
.faq-q {
  margin: 0 0 12px;
  font-size: clamp(20px, 1.8vw, 24px);
  font-weight: 500;
  font-variation-settings: "opsz" 22;
  letter-spacing: -0.02em;
  line-height: 1.25;
  text-wrap: balance;
  color: var(--ink);
}
.faq-a {
  margin: 0;
  max-width: 34em;
  font-size: var(--field);
  line-height: 1.6;
  letter-spacing: -0.006em;
  color: var(--ink-body);
  text-wrap: pretty;
}
.faq-a a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: var(--hairline-firm);
}
.faq-a a:hover { text-decoration-color: currentColor; }
@media (max-width: 760px) {
  .faq { grid-template-columns: minmax(0, 1fr); }
}

/* ===========================================================================
   13. THE DEEP END
   The page runs light at the top and deep at the foot, the shape of
   tryola.ai's own page, which also rounds the top of its deep ground off the
   page. Ink and glass take their on-deep variants.
   =========================================================================== */

.deep {
  position: relative;
  background: linear-gradient(180deg, var(--ground-dark) 0%, var(--ground-dark-2) 100%);
  color: var(--ink-on-deep);
  border-radius: clamp(28px, 4vw, 56px) clamp(28px, 4vw, 56px) 0 0;
  overflow: hidden;
}
.deep::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(58% 46% at 50% 0%, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0) 68%);
}
.deep .h2 { color: var(--ink-on-deep); }
.deep .lede, .deep .note { color: var(--ink-on-deep-2); }

.contact { text-align: center; }
.contact .lede { margin-inline: auto; max-width: 31em; }
.reach {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px 34px;
  margin: clamp(30px, 4.5vh, 46px) 0 0;
}
.mail {
  display: inline-block;
  font-size: clamp(21px, 2.4vw, 30px);
  font-weight: 400;
  font-variation-settings: "opsz" 26;
  letter-spacing: -0.024em;
  color: var(--ink-on-deep);
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.28);
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
  transition: text-decoration-color .3s var(--ease);
}
.mail:hover { text-decoration-color: currentColor; }
.mail.tel { font-variant-numeric: tabular-nums; }

/* --- elsewhere -----------------------------------------------------------
   The circular glass of tryola.ai's own submit button (ola.css `.go`), on the
   deep ground, with its spring on the press. Three marks, evenly weighted, so
   the row reads as a considered part of the sign-off rather than a badge strip.
   ------------------------------------------------------------------------- */
.social {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin: clamp(30px, 4.5vh, 46px) 0 0;
}
.social a {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  color: var(--ink-on-deep);
  text-decoration: none;
  background: linear-gradient(-75deg, rgba(255,255,255,.05), rgba(255,255,255,.14) 48%, rgba(255,255,255,.05));
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.22),
    inset 0 -1px 1px rgba(0, 0, 0, 0.30),
    0 10px 24px -12px rgba(0, 0, 0, 0.7);
  transition: transform .34s var(--spring), background-color .26s var(--ease), box-shadow .26s var(--ease);
}
.social a svg { width: 19px; height: 19px; fill: currentColor; }
.social a:hover {
  transform: translateY(-2px);
  background-color: rgba(255, 255, 255, 0.10);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.34),
    inset 0 -1px 1px rgba(0, 0, 0, 0.30),
    0 14px 30px -12px rgba(0, 0, 0, 0.8);
}
.social a:active { transform: translateY(0) scale(0.95); }
@media (prefers-reduced-motion: reduce) { .social a { transition: none; } }

/* The signature writes itself once, on arrival. Its optical centre is a
   third of the way in (the long tail is a thin flourish, not weight), so it
   is that point, not the middle of the box, that sits on the page axis. */
.sign {
  --w: min(260px, 60vw);
  --write: 2.2s;
  display: block;
  width: var(--w);
  height: auto;
  margin: clamp(34px, 5vh, 54px) auto 0;
  transform: translateX(calc(var(--w) * 0.17));
  color: var(--ink-on-deep);
  opacity: 0.9;
  overflow: visible;
}
.sign .pen {
  fill: none;
  stroke: #fff;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1 3;
  stroke-dashoffset: 0;
}
.sign.is-armed .pen { stroke-dashoffset: 1.02; }
.sign.is-writing .pen {
  animation: pen calc(var(--l) * var(--write)) linear calc(var(--s) * var(--write)) both;
}
@keyframes pen { from { stroke-dashoffset: 1.02; } to { stroke-dashoffset: 0; } }

.foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  max-width: var(--measure);
  margin: clamp(48px, 7vh, 80px) auto 0;
  padding-top: 26px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: var(--micro);
  color: var(--ink-on-deep-2);
}
.foot a { color: rgba(255, 255, 255, 0.8); text-decoration: none; }
.foot a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }

/* ===========================================================================
   14. KEPT, UNUSED
   The Wealth AI live indicator has had no markup since September. Whether
   its CSS goes is still an open question for Jayden, so it stays as it was.
   =========================================================================== */

/* a live indicator. anything.com's pulsing-dot, 1.5s, scale 1 -> 1.15. */
.live {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 6px 14px 6px 11px;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.7);
  box-shadow: inset 0 0 0 1px var(--glass-edge);
  font-size: var(--micro);
  color: var(--ink-body);
}
.live i {
  width: 7px; height: 7px; border-radius: 50%;
  background: #2E9E63;
  box-shadow: 0 0 10px rgba(46, 158, 99, 0.5);
  animation: pulsing-dot 1.5s ease-in-out infinite;
}
@keyframes pulsing-dot { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.15); } }
@media (prefers-reduced-motion: reduce) { .live i { animation: none; } }

/* ===========================================================================
   15. SMALLER SCREENS
   =========================================================================== */

@media (max-width: 980px) {
  .hero-grid { grid-template-columns: 1fr; gap: 40px; }
  .portrait { justify-self: start; max-width: 380px; }

  .ola-intro { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; gap: 48px; }
  .ola-words .lede { margin-inline: auto; }

  .asks { align-items: center; }
  .ask + .ask { margin-left: 0; }
}

@media (max-width: 1099px) {
  /* three across, still in order: LAUNCH 2+1, the three portraits, WHU 2+1,
     then 1+1+1 twice with the aside last */
  .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .card-aside { grid-column: span 1; }
}

@media (max-width: 760px) {
  .frame { top: 12px; height: 50px; padding: 0 7px 0 18px; gap: 10px; }
  .wordmark { font-size: 17px; }
  .wordmark-rest { width: 56px; }
  .wordmark.is-mark { margin-inline-end: -54px; }
  .frame-nav, .frame-rule { display: none; }
  .pill { height: 36px; padding: 0 15px; font-size: 13.5px; }

  .band { padding: clamp(72px, 11vh, 108px) var(--gutter); }
  .hero { padding-top: clamp(104px, 14vh, 140px); padding-bottom: clamp(48px, 7vh, 72px); }
  .hero-grid { margin-top: 26px; }

  .btn { height: 46px; width: 100%; }
  .cta-row { gap: 10px; }
  .cta-row .btn { width: auto; flex: 1 1 auto; min-width: 150px; }

  .phone { width: min(270px, 72vw); }
  .ask { height: 46px; padding: 0 20px; font-size: 15px; }

  .ola-stage { --stage-h: min(360px, 92vw); margin-top: calc(clamp(72px, 11vh, 108px) * -0.45); }
  .cap { height: 46px; padding: 0 17px; font-size: 15px; }
  .does { gap: 10px; margin-top: 52px; }
  .does .set { gap: 10px; }
  .ask { font-size: 14px; padding: 12px 19px; min-height: 46px; text-align: left; }


  /* two across; a photograph's card takes the full width and lays its
     photograph beside its words */
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .card { padding: 7px; border-radius: 20px; }
  .card .tile { height: 70px; border-radius: 14px; }
  .card .tile img { max-height: 28px; }
  .card .t-idealab img { max-height: 34px; }
  .tile .mark { width: 38px; height: 38px; }
  .wm { font-size: 15px; gap: 7px; }
  .t-raisi .wm { font-size: 20px; }
  .card .mask-logo { height: 15px; }
  .card-body { padding: 12px 6px 6px; gap: 4px; }
  .card-t { font-size: 15px; }
  .card-d { font-size: 13px; }
  /* a card with photographs takes the full width and lays them beside
     its words */
  .card-big, .card-tall {
    grid-column: 1 / -1;
    grid-row: auto;
    display: grid;
    grid-template-columns: minmax(0, 44%) minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    column-gap: 4px;
  }
  .card-big .card-photo, .card-tall .card-photo { grid-row: 1 / span 2; aspect-ratio: auto; height: 100%; min-height: 210px; }
  .card-big .tile, .card-tall .tile { margin: 0 0 0 7px; height: 52px; }
  .card-big .card-body, .card-tall .card-body { padding: 12px 6px 6px 13px; }
  .card-aside { grid-column: 1 / -1; padding: 20px; }
  .aside-t { font-size: 17px; }

  .repo-cards { grid-template-columns: minmax(0, 1fr); }
  .demo { height: 176px; }
  .demo-lanes { height: 196px; padding: 15px 14px 12px; font-size: 11px; }
  .ln-row { grid-template-columns: 28px 74px minmax(0, 1fr) 30px; gap: 8px; }

  .foot { justify-content: center; text-align: center; }
}

@media (max-width: 760px) {
  /* phones: one result to a row, in order, newest first; the logo as a
     square beside the words, so no line has to break after every second word */
  .cards { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) {
    display: grid;
    grid-template-columns: 76px minmax(0, 1fr);
    align-items: start;
    column-gap: 4px;
  }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .tile { flex: none; height: 76px; min-height: 0; padding: 0 8px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .tile img { max-width: 100%; max-height: 20px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .t-idealab img { max-height: 24px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .wm { font-size: 11.5px; gap: 5px; white-space: normal; line-height: 1.08; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .wm-stack svg { width: 1.4em; height: 1.4em; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .t-raisi .wm { font-size: 17px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .t-wealth .wm { flex-direction: column; gap: 4px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .t-wealth img { width: 38px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .mask-logo { height: 9px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .tile .mark { width: 32px; height: 32px; }
  .card:not(.card-big):not(.card-tall):not(.card-aside) .card-body { padding: 4px 6px 6px 10px; }
}
