/* ─────────────────────────────────────────────────────────────────────────
   * DEEP LACQUER — shared with studio.html, and that is the point.
   *
   * These two pages used to be two products: index.html in Cinzel on
   * green-black, studio.html in Fraunces on lacquer blue, sharing only the
   * growth green and the seed mark. A visitor crossing from one to the other
   * had no reason to believe they were the same company. So the landing page
   * moved onto the studio's finish rather than the other way round — the studio
   * is the newer, more considered surface, and it is the one with money in it.
   *
   * The reference is unchanged: botanical plate-making rendered in lacquer
   * rather than on paper. A saturated dark ground with real specular depth,
   * wet-looking card surfaces, pale pressed specimens suspended in it.
   *
   * THE ONE RULE THAT MAKES THE PALETTE MEAN SOMETHING: green is not ambient.
   * `--growth` appears only where something is alive or growing — the mark, the
   * ivy on the code card, a live number, the button that starts a grow.
   * Everything else is lacquer and exposed white. `--iron` is the ferric tone
   * and means "planned, not built"; it is the only other accent.
   *
   * If you are editing this file: the tokens below are copied from
   * public/studio.html on purpose. Change one there, change it here.
   * ───────────────────────────────────────────────────────────────────────── */
  :root {
    --abyss:#04101B;          /* deepest ground, behind everything */
    --lacquer:#08202F;        /* the field */
    --lacquer-2:#0D2C40;      /* raised surfaces */
    --lacquer-3:#12384F;      /* hover / lifted */
    --rule:#1C4A63;           /* hairlines */
    --rule-lit:#2C7391;

    --exposed:#EAF2F1;        /* specimen white — silhouettes, display type */
    --text:#DCE8E6;
    --text-dim:#8FAAB0;
    --text-faint:#5B7C86;

    --growth:#6FD08C;         /* ALIVE. Restricted — see the note above. */
    --growth-deep:#3F8F5D;
    --iron:#C97B3C;           /* ferric tone: planned, not built */

    --sheen:rgba(255,255,255,.07);
    --sheen-hi:rgba(255,255,255,.14);

    /* Code colours. A cool keyword, a living string, a warm call, a whispered
     * comment — four hues, so a snippet reads as structure and not as confetti. */
    --tok-k:#7FB6D8;
    --tok-s:var(--growth);
    --tok-f:#E5C173;
    --tok-c:var(--text-faint);

    --display:'Fraunces',Georgia,serif;
    --body:'Archivo',system-ui,-apple-system,sans-serif;
    --mono:'JetBrains Mono',ui-monospace,Menlo,monospace;

    --maxw:1160px;
  }
  * { box-sizing:border-box; }
  html { scroll-behavior:smooth; overflow-x:clip; }
  body {
    margin:0; background:var(--abyss); color:var(--text); line-height:1.6;
    font-family:var(--body); -webkit-font-smoothing:antialiased;
  }
  #page { position:relative; overflow:clip; }

  /* The gloss. Three stacked radial blooms give the ground a wet, lit-from-within
   * depth a flat fill cannot: a specular source top-left, a cool bounce lower
   * right, and a tight green bloom behind the masthead so the one living colour
   * appears to be the thing lighting the page. */
  .ground {
    position:fixed; inset:0; z-index:-2; pointer-events:none;
    background:
      radial-gradient(1200px 760px at 10% -6%, #14415C 0%, transparent 62%),
      radial-gradient(900px 640px at 92% 42%, #0B2E44 0%, transparent 58%),
      radial-gradient(440px 320px at 6% 2%,  rgba(111,208,140,.15) 0%, transparent 70%),
      linear-gradient(#08202F, #04101B 60%);
  }

  /* Pressed specimens, suspended in the lacquer. Matt asked for more of them
   * than the studio carries, and spread down the whole document rather than
   * pinned to the viewport — a long page scrolling past a fixed set of eight
   * reads as wallpaper, whereas plants that arrive and leave read as a plate
   * with material laid all through it. Absolutely positioned inside #page, so
   * the percentages resolve against the full document height.
   *
   * Decorative only: aria-hidden, pointer-events off, and nothing depends on
   * them rendering. */
  .flora { position:absolute; inset:0; z-index:-1; pointer-events:none; }
  .flora svg { position:absolute; fill:var(--exposed); }
  /*      top     side        size   rotate   opacity  */
  .f1  { top:3%;    left:-2%;  width:200px; transform:rotate(-8deg);  opacity:.055; }
  .f2  { top:1%;    right:3%;  width:120px; transform:rotate(12deg);  opacity:.045; }
  .f3  { top:12%;   right:-3%; width:230px; transform:rotate(-4deg);  opacity:.040; }
  .f4  { top:20%;   left:-3%;  width:140px; transform:rotate(6deg);   opacity:.036; }
  .f5  { top:28%;   right:6%;  width:150px; transform:rotate(-14deg); opacity:.030; }
  .f6  { top:36%;   left:4%;   width:100px; transform:rotate(20deg);  opacity:.034; }
  .f7  { top:44%;   right:-4%; width:190px; transform:rotate(-3deg);  opacity:.032; }
  .f8  { top:52%;   left:-2%;  width:110px; transform:rotate(9deg);   opacity:.030; }
  .f9  { top:60%;   right:4%;  width:130px; transform:rotate(-10deg); opacity:.034; }
  .f10 { top:68%;   left:2%;   width:160px; transform:rotate(4deg);   opacity:.028; }
  .f11 { top:76%;   right:-2%; width:120px; transform:rotate(14deg);  opacity:.032; }
  .f12 { top:84%;   left:-3%;  width:180px; transform:rotate(-6deg);  opacity:.030; }
  .f13 { top:91%;   right:5%;  width:140px; transform:rotate(8deg);   opacity:.026; }
  .f14 { bottom:1%; left:6%;   width:110px; transform:rotate(-12deg); opacity:.030; }
  @media (max-width:900px) { .f3,.f5,.f7,.f9,.f11,.f13 { display:none; } }

  .wrap { max-width:var(--maxw); margin:0 auto; padding:0 clamp(1.1rem,4vw,2.5rem); position:relative; }

  /* A grid or flex child defaults to `min-width:auto`, which means its minimum
   * size is its CONTENT's minimum — so a <pre> holding an 80-column line, or a
   * nowrap specimen line, shoves its whole column past the viewport instead of
   * scrolling inside itself. On a 430px phone that cut the headline in half.
   *
   * Every container on this page that can hold code needs this, so it is
   * declared once here rather than discovered again per section. The
   * `overflow-x` on `pre` and `.utter` is what then does the scrolling. */
  .hero-grid > *, .doors > *, .grid > *, .plans > *, .steps > *, .step > * { min-width:0; }

  /* ── type ───────────────────────────────────────────────────────────────── */
  h1, h2, h3 { font-family:var(--display); color:var(--exposed); font-weight:600;
    letter-spacing:-.015em; }
  h1 { font-size:clamp(2.1rem,5vw,3.4rem); line-height:1.06; margin:.6rem 0 0; }
  h1 .accent { color:var(--growth); }
  h2.sec { font-size:clamp(1.5rem,3vw,2.1rem); line-height:1.14; margin:.4rem 0 .8rem; }
  h3 { font-size:1.06rem; margin:0 0 .4rem; letter-spacing:-.005em; }
  p { margin:.5rem 0; }
  a { color:var(--growth); text-decoration:none; }
  a:hover { text-decoration:underline; }

  /* Monospace is a CO-LEAD on this product, not a utility face: every specimen
   * carries a scientific name, a habit, a rung, a tri count and a height in
   * metres, so the measured quantities are set in the face that says measured. */
  .eyebrow { font-family:var(--mono); font-size:.64rem; letter-spacing:.2em;
    text-transform:uppercase; color:var(--text-faint); margin:0 0 .9rem; }
  .lede { font-size:clamp(1.02rem,1.6vw,1.16rem); color:var(--text-dim); max-width:52ch;
    margin:1.2rem 0 0; }
  .sec-lede { color:var(--text-dim); max-width:62ch; margin:0 0 2rem; }
  code, .mono { font-family:var(--mono); }
  code { background:#061A26; padding:.12rem .4rem; border-radius:5px; color:var(--growth);
    font-size:.86em; }

  /* ── chrome ─────────────────────────────────────────────────────────────── */
  .topbar {
    position:sticky; top:0; z-index:40;
    background:linear-gradient(rgba(8,32,47,.92), rgba(8,32,47,.72));
    backdrop-filter:blur(14px) saturate(1.3);
    border-bottom:1px solid var(--rule);
    box-shadow:0 1px 0 var(--sheen), 0 12px 34px -18px #000;
  }
  .topbar .wrap { display:flex; align-items:center; justify-content:space-between; height:60px; }
  .brand { display:flex; align-items:baseline; gap:.55rem; font-family:var(--display);
    font-weight:600; font-size:1.06rem; }
  /* The mark: a living seed with a wet highlight. The only unrestrained specular
   * on the page — it is the one thing that is alive. */
  .brand .dot {
    width:13px; height:13px; border-radius:50%; align-self:center;
    background:radial-gradient(circle at 32% 28%, #C9F5D8 0%, var(--growth) 42%, var(--growth-deep) 100%);
    box-shadow:0 0 16px rgba(111,208,140,.55), inset 0 -1px 2px rgba(0,0,0,.35);
  }
  .navlinks { display:flex; gap:1.4rem; font-size:.86rem; align-items:center; }
  .navlinks a { color:var(--text-dim); }
  .navlinks a:hover { color:var(--exposed); text-decoration:none; }
  .navlinks a.cta { color:var(--growth); }
  @media (max-width:820px) { .navlinks a:not(.cta) { display:none; } }

  /* ── controls ───────────────────────────────────────────────────────────── */
  .btn {
    display:inline-flex; align-items:center; gap:.5rem; font:inherit; font-family:var(--body);
    font-weight:500; padding:.72rem 1.3rem; border-radius:11px; cursor:pointer;
    border:1px solid var(--rule-lit); color:var(--text);
    background:linear-gradient(#154a62, #0e2d42);
    box-shadow:inset 0 1px 0 var(--sheen-hi), 0 6px 16px -10px #000;
    transition:transform .12s ease, box-shadow .12s ease, filter .12s ease;
  }
  .btn:hover { filter:brightness(1.18); transform:translateY(-1px); text-decoration:none; }
  .btn:active { transform:translateY(0); filter:brightness(.95); }
  /* Wet green is reserved for controls that make something grow. There are two
   * on this page, one per door, and no third. */
  .btn.hero {
    background:linear-gradient(#8AE3A5, var(--growth) 46%, var(--growth-deep));
    color:#04210F; border-color:#8AE3A5; font-weight:600; padding:.8rem 1.7rem;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.5), 0 8px 26px -12px rgba(111,208,140,.7);
  }
  .btn.ghost { background:transparent; }
  .btn.ghost:hover { background:var(--lacquer-3); filter:none; }
  /* Not a link: a label for something that is not purchasable yet. No href, no
   * hover lift, dashed to read as planned — the same ◷ vocabulary as li.soon. */
  .btn.coming { background:transparent; border-style:dashed; border-color:var(--rule);
    color:var(--text-faint); cursor:default; font-weight:400; font-size:.86rem; }
  .btn.coming:hover { transform:none; filter:none; }
  .btn.coming::before { content:"◷"; color:var(--iron); }
  :focus-visible { outline:2px solid var(--growth); outline-offset:3px; }

  /* ── lacquered surfaces ─────────────────────────────────────────────────── */
  /* Every card is a poured surface: a bright hairline along the top edge where
   * the light catches, a soft inner glow, and a deep shadow underneath so it
   * reads as a slab sitting ON the ground rather than a box drawn into it. */
  .card {
    position:relative; border:1px solid var(--rule); border-radius:16px;
    background:linear-gradient(165deg, var(--lacquer-2) 0%, var(--lacquer) 58%, #071B28 100%);
    padding:1.5rem 1.6rem;
    box-shadow:
      inset 0 1px 0 var(--sheen-hi),
      inset 0 -18px 40px -30px #000,
      0 20px 44px -26px rgba(0,0,0,.85);
  }
  .card .k { font-family:var(--mono); font-size:.6rem; letter-spacing:.16em;
    text-transform:uppercase; color:var(--growth); margin-bottom:.55rem; }
  .card p { color:var(--text-dim); font-size:.92rem; margin:0; }

  .band { padding:clamp(3rem,7vw,5.5rem) 0; border-top:1px solid var(--rule); }
  .band.alt { background:linear-gradient(rgba(8,32,47,.55), rgba(4,16,27,.2)); }

  /* ── hero ───────────────────────────────────────────────────────────────── */
  .hero { padding:clamp(2.6rem,6vw,4.4rem) 0 clamp(2.6rem,5vw,3.6rem); }
  .hero-grid { display:grid; grid-template-columns:1.02fr 1fr; gap:clamp(2rem,5vw,3.4rem);
    align-items:center; }
  @media (max-width:940px) { .hero-grid { grid-template-columns:1fr; } }
  .trust { margin-top:1.5rem; font-family:var(--mono); font-size:.72rem; letter-spacing:.04em;
    color:var(--text-faint); }
  .trust b { color:var(--growth); font-weight:500; }

  /* ── code ───────────────────────────────────────────────────────────────── */
  .code-card {
    border:1px solid var(--rule); border-radius:14px; overflow:hidden; background:#061A26;
    box-shadow:inset 0 1px 0 var(--sheen), 0 28px 66px -34px #000;
  }
  .code-head { display:flex; align-items:center; gap:.5rem; padding:.6rem .9rem;
    border-bottom:1px solid var(--rule); background:var(--lacquer-2);
    font-family:var(--mono); font-size:.7rem; color:var(--text-faint); }
  .code-head .d { width:9px; height:9px; border-radius:50%; background:var(--rule-lit); }
  .code-head .name { margin-left:auto; letter-spacing:.06em; }
  pre { margin:0; padding:1rem 1.1rem; overflow-x:auto; font-size:.76rem; line-height:1.72;
    font-family:var(--mono); }
  pre code { background:none; padding:0; color:var(--text); font-size:1em; }
  .tok-c { color:var(--tok-c); font-style:italic; }
  .tok-k { color:var(--tok-k); }
  .tok-s { color:var(--tok-s); }
  .tok-f { color:var(--tok-f); }

  /* ── THE SIGNATURE: ivy on the code card ────────────────────────────────── */
  /* Matt's idea, and the best one on the page: the hero's code card — the most
   * characteristic object on any developer landing page — is being colonised by
   * the thing the API returns. The page's own furniture grows over.
   *
   * It is a real species. `climbing-ivy` / Hedera helix / form `vine` is a row
   * in the catalog with ready assets, which is why the caption can name it and
   * link to the specimen. Drawing a generic decorative vine here and captioning
   * it would have been the one dishonest thing on the page.
   *
   * Two fixed-size overlays rather than one stretched to the card: an SVG scaled
   * non-uniformly to fit a responsive box distorts every leaf on it. Fixed
   * pixels, anchored to the corners, so the leaves keep their shape at any width.
   *
   * The overlays sit OUTSIDE .code-card, which clips to its radius — a vine that
   * cannot cross the edge is a border, not a plant. */
  .codewrap { position:relative; }
  .ivy { position:absolute; pointer-events:none; overflow:visible; z-index:2; }
  .ivy-top { top:-38px; left:-30px; width:392px; height:170px; }
  .ivy-foot { right:-22px; bottom:-34px; width:196px; height:146px; }
  @media (max-width:940px) { .ivy-foot { display:none; } }
  @media (max-width:520px) { .ivy-top { width:280px; height:130px; top:-28px; left:-20px; } }

  .ivy .vine { fill:none; stroke:var(--growth-deep); stroke-width:2.4; stroke-linecap:round; }
  /* Drawn on, not faded in. `pathLength="100"` normalises the dash maths so the
   * same two declarations work on any path without measuring it in script. */
  .ivy .vine { stroke-dasharray:100; stroke-dashoffset:100;
    animation:vine-grow 2.6s cubic-bezier(.42,.08,.3,1) both; }
  @keyframes vine-grow { to { stroke-dashoffset:0; } }

  /* Leaves unfurl from the petiole, timed off --d so each one opens just after
   * the stem reaches it. `transform-box:fill-box` is what lets the origin be the
   * leaf's own stem end rather than the SVG's corner. */
  .ivy .lf { color:var(--growth-deep); opacity:0;
    transform-box:fill-box; transform-origin:50% 100%;
    animation:leaf-out .72s cubic-bezier(.2,.75,.3,1) both; animation-delay:var(--d,0s); }
  @keyframes leaf-out {
    from { opacity:0; transform:scale(.15) rotate(-14deg); }
    to   { opacity:.92; transform:none; }
  }
  /* A handful of leaves catch the light — the same trick as the ground's third
   * bloom, so the vine reads as lit from the top-left like everything else. */
  .ivy .lf.lit { color:var(--growth); }

  /* The herbarium caption. Sits under the card in the accession-label voice the
   * studio uses on every result plate: scientific name in the display face,
   * everything measured in mono. */
  .ivy-cap {
    display:flex; flex-wrap:wrap; gap:.35rem .8rem; align-items:baseline;
    margin:.85rem .2rem 0; font-family:var(--mono); font-size:.66rem;
    letter-spacing:.04em; color:var(--text-faint);
  }
  .ivy-cap .sci { font-family:var(--display); font-style:italic; font-size:.82rem;
    color:var(--text-dim); }
  .ivy-cap a:hover { color:var(--growth); }

  /* ── the two doors ──────────────────────────────────────────────────────── */
  /* The whole ask: show the two ways in, side by side, neither buried.
   *
   * The structural idea is that ONE DOOR SPEAKS HTTP AND THE OTHER SPEAKS
   * ENGLISH, so each carries a specimen line in its own language — a GET on the
   * left, a sentence you would actually type on the right. That is a true
   * difference between the products, not a decorative pairing, and it means a
   * visitor can tell them apart before reading a word of prose. */
  .doors { display:grid; grid-template-columns:1fr 1fr; gap:clamp(1rem,2.4vw,1.6rem);
    margin-top:clamp(2.4rem,5vw,3.4rem); }
  @media (max-width:820px) { .doors { grid-template-columns:1fr; } }
  .door { display:flex; flex-direction:column; gap:.9rem; padding:1.7rem 1.7rem 1.6rem;
    transition:border-color .25s ease, box-shadow .3s ease, transform .25s ease; }
  .door:hover { transform:translateY(-3px); border-color:var(--rule-lit);
    box-shadow:inset 0 1px 0 var(--sheen-hi), 0 30px 60px -30px rgba(0,0,0,.9); }
  .door h3 { font-size:1.28rem; margin:0; }
  .door > p { font-size:.94rem; }
  .door .price { font-family:var(--mono); font-size:.68rem; letter-spacing:.16em;
    text-transform:uppercase; color:var(--growth); }
  .door.studio { border-color:var(--growth-deep);
    box-shadow:inset 0 1px 0 var(--sheen-hi), 0 20px 44px -26px rgba(0,0,0,.85),
               0 0 70px -40px rgba(111,208,140,.6); }
  .acts { display:flex; flex-wrap:wrap; gap:.6rem; align-items:center; }
  .door .acts { margin-top:auto; padding-top:.5rem; }

  /* The specimen line: one utterance in the door's own language, set on the
   * sunken ground so it reads as an input rather than as prose. */
  .utter { border:1px solid var(--rule); border-radius:10px; background:#061A26;
    padding:.7rem .85rem; font-family:var(--mono); font-size:.74rem; line-height:1.6;
    color:var(--text-dim); box-shadow:inset 0 2px 10px -6px #000; overflow-x:auto;
    white-space:nowrap; }
  .utter .m { color:var(--tok-f); }
  .utter .q { color:var(--growth); }
  .utter.said { font-family:var(--body); font-size:.92rem; color:var(--text);
    white-space:normal; }
  .utter.said::before { content:'“'; color:var(--text-faint); }
  .utter.said::after { content:'”'; color:var(--text-faint); }

  /* ── steps ──────────────────────────────────────────────────────────────── */
  /* Numbered because this genuinely IS a sequence — you cannot instance a plan
   * you have not resolved. The markers earn themselves here; they would be
   * decoration on the feature grid, which is why that has none. */
  .steps { display:flex; flex-direction:column; gap:2.4rem; }
  .step { display:grid; grid-template-columns:auto 1fr; gap:1.2rem; align-items:start; }
  .step .n { width:34px; height:34px; border-radius:50%; display:grid; place-items:center;
    font-family:var(--mono); font-size:.86rem; color:var(--growth);
    border:1px solid var(--growth-deep); background:rgba(111,208,140,.08); }
  .step p { color:var(--text-dim); font-size:.94rem; max-width:66ch; }
  .step .code-card { margin-top:1rem; }

  /* ── stats ──────────────────────────────────────────────────────────────── */
  .stats { display:grid; grid-template-columns:repeat(4,1fr); gap:1rem; margin:2rem 0 .6rem; }
  @media (max-width:760px) { .stats { grid-template-columns:repeat(2,1fr); } }
  .stat { border:1px solid var(--rule); border-radius:13px; padding:1.1rem 1.2rem;
    background:linear-gradient(165deg, rgba(19,58,82,.5), rgba(8,32,47,.5));
    box-shadow:inset 0 1px 0 var(--sheen); }
  .stat .v { font-family:var(--mono); font-size:1.42rem; color:var(--exposed);
    font-variant-numeric:tabular-nums; line-height:1.2; }
  .stat .l { font-family:var(--mono); font-size:.6rem; letter-spacing:.14em;
    text-transform:uppercase; color:var(--text-faint); margin-top:.3rem; }
  .stat.hi { border-color:var(--growth-deep); background:rgba(111,208,140,.07); }
  .stat.hi .v { color:var(--growth); }
  .fp-note { font-family:var(--mono); font-size:.66rem; color:var(--text-faint);
    letter-spacing:.04em; margin:0 0 2rem; }

  /* ── feature grid ───────────────────────────────────────────────────────── */
  /* 300px, not 255: both grids on this page hold three or six cards, and a
   * 255px minimum fits four across at full width — which leaves the six-card
   * grid with two orphans on a second row. Three-up divides both of them. */
  .grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:1.1rem; }

  /* ── specimen strip ─────────────────────────────────────────────────────── */
  .strip { display:grid; grid-auto-flow:column; grid-auto-columns:minmax(150px,1fr);
    gap:.9rem; overflow-x:auto; padding-bottom:.6rem; margin-bottom:1.6rem;
    scroll-snap-type:x proximity; }
  .strip a { scroll-snap-align:start; border:1px solid var(--rule); border-radius:13px;
    overflow:hidden; background:#061A26; text-decoration:none;
    box-shadow:inset 0 1px 0 var(--sheen); transition:border-color .2s, transform .2s; }
  .strip a:hover { border-color:var(--growth-deep); transform:translateY(-3px);
    text-decoration:none; }
  .strip img { display:block; width:100%; aspect-ratio:1; object-fit:contain;
    background:radial-gradient(120% 90% at 50% 0%, #12384F 0%, transparent 62%); }
  .strip .cap { padding:.5rem .7rem; font-family:var(--mono); font-size:.62rem;
    letter-spacing:.04em; color:var(--text-faint); border-top:1px solid var(--rule); }

  /* ── plans ──────────────────────────────────────────────────────────────── */
  .plans { display:grid; grid-template-columns:repeat(3,1fr); gap:1.2rem; align-items:start; }
  @media (max-width:900px) { .plans { grid-template-columns:1fr; } }
  .plan { display:flex; flex-direction:column; gap:.5rem; }
  .plan .tier { font-family:var(--mono); font-size:.6rem; letter-spacing:.18em;
    text-transform:uppercase; color:var(--text-faint); }
  .plan .pname { font-family:var(--display); font-size:1.24rem; color:var(--exposed);
    font-weight:600; }
  .plan .price { font-family:var(--mono); font-size:1.9rem; color:var(--exposed);
    font-variant-numeric:tabular-nums; line-height:1.1; }
  .plan .price small { font-size:.72rem; color:var(--text-faint); letter-spacing:.06em; }
  .plan .who { color:var(--text-dim); font-size:.86rem; min-height:2.6em; }
  .plan ul { list-style:none; padding:0; margin:.6rem 0 1.2rem; font-size:.88rem;
    color:var(--text-dim); }
  .plan li { padding:.32rem 0 .32rem 1.4rem; position:relative; }
  .plan li::before { content:'·'; position:absolute; left:.35rem; color:var(--growth); }
  .plan li.soon::before { content:'◷'; font-size:.72em; left:.2rem; color:var(--iron); }
  .plan li.soon { color:var(--text-faint); }
  .plan.featured { border-color:var(--growth-deep);
    box-shadow:inset 0 1px 0 var(--sheen-hi), 0 24px 52px -28px rgba(0,0,0,.9),
               0 0 80px -44px rgba(111,208,140,.55); }
  .plan .btn-stack { display:flex; flex-direction:column; gap:.55rem; align-items:flex-start;
    margin-top:auto; }
  .plan > .btn { margin-top:auto; align-self:flex-start; }

  .meter-note { margin-top:2rem; border:1px solid var(--rule); border-left:2px solid var(--growth-deep);
    border-radius:0 13px 13px 0; padding:1.1rem 1.3rem; background:rgba(6,26,38,.6);
    color:var(--text-dim); font-size:.88rem; }
  .meter-note b { color:var(--exposed); font-weight:500; }
  .fineprint { margin-top:1.4rem; font-size:.78rem; color:var(--text-faint); max-width:70ch; }

  /* ── footer ─────────────────────────────────────────────────────────────── */
  footer { border-top:1px solid var(--rule); padding:2.6rem 0 3rem;
    background:linear-gradient(rgba(4,16,27,.4), rgba(4,16,27,.9)); }
  footer .wrap { display:flex; flex-wrap:wrap; gap:2rem; justify-content:space-between;
    font-size:.86rem; color:var(--text-dim); }
  footer .foot-note { max-width:44ch; }
  footer .cols { font-family:var(--mono); font-size:.74rem; }
  footer .cols .h { color:var(--text-faint); letter-spacing:.14em; text-transform:uppercase;
    font-size:.6rem; margin-bottom:.5rem; }

  /* ── scroll reveal ──────────────────────────────────────────────────────── */
  /* The same develop curve as the studio's result plates: pale and soft, then
   * resolved. One idea for arrival, used everywhere. */
  .reveal { opacity:0; transform:translateY(14px); filter:blur(2px);
    transition:opacity .7s cubic-bezier(.2,.7,.3,1), transform .7s cubic-bezier(.2,.7,.3,1),
               filter .7s ease; }
  .reveal.in { opacity:1; transform:none; filter:none; }

  @media (prefers-reduced-motion:reduce) {
    html { scroll-behavior:auto; }
    .reveal { opacity:1; transform:none; filter:none; transition:none; }
    .ivy .vine { animation:none; stroke-dashoffset:0; }
    .ivy .lf { animation:none; opacity:.92; }
    .door:hover, .btn:hover, .strip a:hover { transform:none; }
  }

  /* ── THE PORTAL ──────────────────────────────────────────────────────────────
   * One tree on a page is a picture; a tree you can step into is the product. The
   * specimen is a live catalog thumbnail and the destination is a really-generated
   * grove, so the frame should read as an aperture onto somewhere rather than as a
   * card with an image in it.
   *
   * The glow is a conic gradient rotated by a custom property, which the compositor
   * can animate on its own thread — a rotating pseudo-element would repaint the ring
   * every frame. --growth is the restricted "alive" accent, and this is the one place
   * on the page that earns it: it is the only element that leads somewhere living. */
  @property --portal-spin { syntax:'<angle>'; initial-value:0deg; inherits:false; }

  .portal-band { display:grid; grid-template-columns:minmax(0,1fr); gap:2rem; align-items:center; }
  @media (min-width:820px) { .portal-band { grid-template-columns:auto minmax(0,1fr); gap:3rem; } }

  .portal {
    position:relative; display:block; flex:none;
    width:min(300px,68vw); aspect-ratio:1; border-radius:50%;
    padding:3px; text-decoration:none; isolation:isolate;
    background:conic-gradient(from var(--portal-spin),
      transparent 0deg, var(--rule-lit) 70deg, var(--growth) 140deg,
      var(--rule-lit) 210deg, transparent 300deg);
    animation:portal-spin 14s linear infinite;
    transition:transform .5s cubic-bezier(.2,.8,.25,1), filter .5s ease;
  }
  @keyframes portal-spin { to { --portal-spin:360deg; } }

  /* The aperture itself: the image sits BEHIND a soft vignette so the edge dissolves
   * into the page instead of stopping at a hard circle — that dissolve is most of
   * what makes it read as depth rather than as a round photo. */
  .portal-eye {
    position:relative; width:100%; height:100%; border-radius:50%; overflow:hidden;
    background:radial-gradient(circle at 50% 42%, var(--lacquer-2), var(--abyss) 78%);
    box-shadow:inset 0 0 60px 18px rgba(4,16,27,.92), inset 0 2px 0 var(--sheen);
  }
  .portal-eye img {
    width:100%; height:100%; object-fit:cover; display:block;
    transform:scale(1.06); transition:transform .6s cubic-bezier(.2,.8,.25,1);
    -webkit-mask-image:radial-gradient(circle at 50% 50%, #000 52%, transparent 78%);
            mask-image:radial-gradient(circle at 50% 50%, #000 52%, transparent 78%);
  }
  .portal:hover { transform:scale(1.03); filter:drop-shadow(0 0 28px rgba(111,208,140,.28)); }
  .portal:hover .portal-eye img { transform:scale(1.14); }
  .portal:focus-visible { outline:2px solid var(--growth); outline-offset:6px; }

  /* "Walk in" only appears on approach — a label that is always on turns the
   * aperture back into a button. */
  .portal-cue {
    position:absolute; left:50%; bottom:13%; transform:translate(-50%,6px);
    font-size:.72rem; letter-spacing:.12em; text-transform:uppercase;
    color:var(--exposed); opacity:0; transition:opacity .4s ease, transform .4s ease;
    text-shadow:0 2px 12px var(--abyss); pointer-events:none; white-space:nowrap;
  }
  .portal:hover .portal-cue, .portal:focus-visible .portal-cue { opacity:1; transform:translate(-50%,0); }

  @media (prefers-reduced-motion:reduce) {
    .portal { animation:none; transition:none; }
    .portal-eye img, .portal-cue { transition:none; }
    .portal-cue { opacity:1; transform:translate(-50%,0); }   /* never hide the affordance */
  }
