/* ==========================================================
   BM Labs — marketing pages (home + one page per app)
   Each app page sets its accent on <html style="--ac:…">

   This is the stylesheet for index.html and <slug>/index.html only.
   The legal pages (<slug>/privacy.html, terms.html) are generated by
   `legal-build` and still load assets/style.css — do not merge the two.
   ========================================================== */

:root{
  --ac:#2563EB;
  --ac-btn:var(--ac); /* the accent as a text-bearing surface; == --ac unless it had to shift */
  --on-ac:#FFFFFF;    /* whichever of white / near-black clears 4.5:1 on --ac-btn */
  --font:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",system-ui,sans-serif;
  /* The nav is a floating capsule, so what the hero has to clear is the capsule plus the air
     above it. The bar this replaced wrote its 64px in three places — the nav, the nav's inner
     row and the hero's min-height — so the height is one token and the rest is derived. */
  --nav-cap:56px;
  --nav-gap:14px;
  --nav-h:calc(var(--nav-cap) + var(--nav-gap));
  /* How tall the hero is allowed to get. Read twice: the hero's own min-height, and the width
     the device is sized to, which is what keeps the two from drifting apart. */
  --hero-max:860px;

  /* One palette. The site was three-state — an explicit `data-theme`, a `prefers-color-scheme`
     fallback and a toggle that wrote localStorage — and every colour had to be defined twice for
     it. The apps are dark, the shots are dark, and the light rendering was a second design nobody
     was looking at. `color-scheme` is what tells the browser to draw its own furniture (scrollbars,
     form controls, the space behind an over-scroll) to match. */
  color-scheme:dark;
  --bg:#08090C;
  --bg-2:#111419;
  --fg:#F5F7F9;
  --fg-2:#A5ADB8;
  --fg-3:#7A828D;
  --line:rgba(245,247,249,.13);
  --bezel:#1C1F25;
  --bezel-edge:rgba(255,255,255,.16);
  --btn-bg:#F5F7F9;
  --btn-fg:#08090C;
  --glow:20%;
  --shadow:0 40px 100px -30px rgba(0,0,0,.9), 0 8px 30px -8px rgba(0,0,0,.6);
}

*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  background:var(--bg);color:var(--fg);
  font-family:var(--font);font-size:17px;line-height:1.5;
  letter-spacing:-.015em;-webkit-font-smoothing:antialiased;
  overflow-x:hidden;
  /* The hero is capped, so on a tall display the page can be shorter than the window. This puts
     the footer on the bottom edge rather than leaving a band of bare background under it. */
  min-height:100svh;display:flex;flex-direction:column;
}
body > main{flex:1 0 auto}
/* `height:auto` is not decoration: every <img> carries width/height attributes so the box is
   reserved before the file loads, and those attributes are ALSO presentational hints. Any rule
   that sets width without releasing height leaves the hint standing — .phone img{width:100%}
   was rendering a 600×1304 shot at 296×1304, a 4.4× vertical stretch, on all seven app pages. */
img{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--ac);outline-offset:4px;border-radius:8px}
.wrap{max-width:1000px;margin:0 auto;padding:0 clamp(20px,5vw,32px)}
.skip{position:absolute;left:-9999px;background:var(--fg);color:var(--bg);padding:10px 16px;z-index:200}
.skip:focus{left:12px;top:12px}

/* ---------------- nav ---------------- */
/* A floating capsule rather than a full-width bar. The bar ruled a hard line across the top of
   every page and made the hero start inside a box below it; the capsule sits ON the hero, the
   accent glow passes behind it, and the page reads as one surface. Three groups: the brand at the
   left, the links pinned to the true centre (absolute — a flex `margin:auto` centres them
   between two unequal neighbours, which is not the centre), the controls at the right. */
.nav{position:sticky;top:0;z-index:50;padding:var(--nav-gap) clamp(8px,2.5vw,18px) 0}
.nav .nav-in{
  position:relative;display:flex;align-items:center;gap:14px;
  height:var(--nav-cap);padding:0 10px 0 clamp(14px,2vw,20px);
  border-radius:99px;border:1px solid var(--line);
  background:color-mix(in srgb,var(--bg-2) 84%,transparent);
  backdrop-filter:saturate(180%) blur(20px);
  -webkit-backdrop-filter:saturate(180%) blur(20px);
  box-shadow:0 14px 34px -22px rgba(10,12,15,.5);
}
.nav-links{
  position:absolute;left:50%;transform:translateX(-50%);
  display:flex;align-items:center;gap:clamp(16px,2.6vw,30px);
}
.nav-right{display:flex;align-items:center;gap:10px;margin-left:auto}
/* The hub and the 404 carry nothing but the mark — everything their bar used to hold is in the
   footer under it. A 1000px capsule with a logo at one end reads as a row that lost its contents,
   so it shrinks to what it holds and centres, the way the page beneath it is centred. */
.nav-brand-only .nav-in{width:fit-content;padding-right:clamp(14px,2vw,20px)}
.brand{display:flex;align-items:center;gap:10px;margin-right:auto;font-weight:600;font-size:16.5px}
/* No radius on any icon in this file: every PNG under assets/icons carries its own iOS mask
   now (assets/shots/make-shots.py), and a CSS corner on top of it is a second, rounder shape
   clipping the first — which is how the same file came to look square in the browser tab and
   rounded everywhere else. */
.brand img{width:30px;height:30px}
.brand .sup{display:block;font-size:11.5px;font-weight:500;color:var(--fg-3);margin-top:-3px;letter-spacing:0}
.nl{font-size:14.5px;font-weight:500;color:var(--fg-2);transition:color .18s}
.nl:hover{color:var(--fg)}
/* The gutter beside the capsule is empty again: it held the appearance toggle, which a one-theme
   site has nothing to toggle. */
@media(max-width:860px){.nav-links{display:none}}
/* On the narrowest phones the capsule's three groups only just fit; below this it is the CTA that
   would be pushed off, so the whole bar tightens rather than any one part being dropped. */
@media(max-width:430px){
  .nav{padding-left:8px;padding-right:8px}
  .nav .nav-in{gap:8px;padding:0 8px 0 12px}
  .brand{font-size:15px}
  .brand img{width:26px;height:26px}
  .btn-sm{padding:8px 14px;font-size:13.5px}
}

/* ---------------- buttons ---------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  background:var(--btn-bg);color:var(--btn-fg);
  font-size:16px;font-weight:600;padding:14px 26px;border-radius:99px;
  transition:transform .2s cubic-bezier(.22,1,.36,1),opacity .2s;
  white-space:nowrap;
}
.btn:hover{transform:translateY(-2px);opacity:.92}
.btn svg{width:19px;height:19px;fill:currentColor;margin-top:-2px}
.btn-sm{padding:9px 18px;font-size:14.5px}
.btn-sm svg{width:16px;height:16px}
.btn-ac{background:var(--ac-btn);color:var(--on-ac)}
/* Coming-soon apps have nothing to download — an outline button, not a filled one. */
.btn-ghost{background:none;color:var(--fg);border:1px solid var(--line)}
.btn-ghost:hover{border-color:var(--fg-3);opacity:1}

/* ---------------- hero (the whole page) ---------------- */
/* The copy reads down the left, the device stands whole on the right. Before this the page
   centred everything and dropped a 310px phone underneath, which is the layout every template
   ships and says nothing about the app. */
/* One item, one track, pinned: an implicit `auto` track is sized from its content, and there is
   nothing to gain from letting the hero's own column do that.
   `overflow-x:clip`, not `hidden`: the glow below has to spill UPWARDS over the nav — `hidden`
   drew a hard horizontal edge across the page at exactly the height the nav ends, the one place a
   soft light must not have a seam — while still being cut at the sides, because at 500px it is
   wider than the window and left the page pannable (scrollWidth 645 against a 500px viewport).
   `clip` is the only value that takes one axis and leaves the other visible. */
.hero{position:relative;overflow-x:clip;display:grid;grid-template-columns:minmax(0,1fr);align-content:center}
.hero::before{
  /* Anchored above the page, not to a share of the hero's height: the light has to reach over the
     nav, and the nav's own height is the one number that says how far that is. The capsule is
     translucent, so it takes the colour rather than blocking it. */
  content:"";position:absolute;top:calc(-1 * var(--nav-h) - 210px);left:64%;transform:translateX(-50%);
  width:min(1000px,130%);aspect-ratio:1.4;pointer-events:none;
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--ac) var(--glow),transparent), transparent 72%);
}
.hero-in{
  position:relative;z-index:1;
  /* Capped, not just `100svh - nav`. The device is sized from this height and has to fit its
     column too, so on a 1600px window an uncapped hero would ask for a 543px-wide phone in a
     ~480px column — it would fall short and open a hole beside itself, 660px of one. */
  min-height:min(calc(100svh - var(--nav-h)),var(--hero-max));
  display:grid;grid-template-columns:minmax(0,1.02fr) minmax(0,.98fr);
  /* No padding-top: the row is centred, so any padding here lands only on the top and the device
     ends up with more air above it than below — the asymmetry this file just spent a revision
     removing. The narrow layout, which stacks instead of centring, sets its own. */
  align-items:center;gap:clamp(20px,4vw,56px);
}
.hero-copy{display:flex;flex-direction:column;align-items:flex-start;text-align:left}

/* One column, centred: the 404 page, and any app whose shot is missing. */
.hero-in.solo{grid-template-columns:minmax(0,1fr);justify-items:center}
.solo .hero-copy{align-items:center;text-align:center}
.solo h1{max-width:20ch}

/* The category, which used to be the h1. Shared with the home page's eyebrow. */
.eyebrow{
  display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:99px;
  padding:7px 15px;font-size:13.5px;font-weight:500;color:var(--fg-2);
  background:color-mix(in srgb,var(--bg-2) 70%,transparent);margin-bottom:22px;
}

.rating{display:flex;align-items:center;gap:10px;margin-bottom:22px}
.stars{display:flex;gap:2px}
.stars svg{width:15px;height:15px;fill:var(--ac)}
.rating .val{font-size:15px;font-weight:700}
.rating .cap{font-size:14px;color:var(--fg-3)}

.hero h1{
  font-size:clamp(38px,5.4vw,64px);font-weight:800;
  line-height:1.0;letter-spacing:-.045em;
  max-width:14ch;margin-bottom:18px;
}
.hero .lede{
  font-size:clamp(17px,1.8vw,20px);color:var(--fg-2);
  line-height:1.55;max-width:44ch;margin-bottom:30px;
}
.hero .meta{
  display:flex;flex-wrap:wrap;gap:6px 20px;
  margin-top:18px;font-size:14px;color:var(--fg-3);
}
.hero .meta span{display:inline-flex;align-items:center;gap:6px}
.hero .meta i{width:5px;height:5px;border-radius:99px;background:var(--ac);font-style:normal}

/* The meta row's stand-in on an unreleased app: one status, not three claims. */
.status{
  display:inline-flex;align-items:center;gap:7px;margin-top:20px;
  border:1px solid var(--line);border-radius:99px;padding:7px 15px;
  font-size:13.5px;font-weight:500;color:var(--fg-2);
  background:color-mix(in srgb,var(--bg-2) 70%,transparent);
}
.status svg{width:14px;height:14px;fill:none;stroke:var(--ac);stroke-width:1.9;stroke-linecap:round}

/* THE WHOLE DEVICE IS SHOWN. The only thing allowed to run past an edge is the app's own screen
   inside the phone, cut by the phone's bezel — the way it is cut on a real device. The chassis
   itself was being sliced by the fold, and a phone whose bottom half is missing does not read as
   a screenshot of a phone, it reads as a broken image.
   That is why the width is derived from the HEIGHT available rather than from the column: .413 of
   the hero leaves as much room above the device as below it, and it fits at every window height by
   construction rather than by luck. Nothing anchors it — `align-items:center` on the row splits
   what is left over evenly, which is what keeps the two margins equal as the window changes. */
.shot{
  justify-self:center;
  width:min(34vw, calc(min(100svh - var(--nav-h),var(--hero-max)) * .413), 360px);
}
/* On a dark page a pure-black bezel around a dark screenshot is not a device, it is a hole: the
   frame, the page and the app's own background were all within a few points of #000. The bezel is
   lifted off the page and given a hairline edge, which is what a real chassis catches. */
.phone{
  background:var(--bezel);
  border:1px solid var(--bezel-edge);
  border-radius:clamp(34px,4.6vw,52px);
  padding:clamp(7px,1vw,10px);
  box-shadow:var(--shadow);
  /* No Dynamic Island is drawn here: assets/shots/*.webp are real device screens that already
     carry one, and a second pill on top of the first reads as a rendering bug. */
}
.phone img{border-radius:clamp(28px,3.8vw,43px);width:100%}

/* Narrow: one column, centred, the device under the copy and still cut by the fold. */
@media(max-width:940px){
  .hero-in{
    grid-template-columns:minmax(0,1fr);justify-items:center;align-content:start;
    gap:clamp(24px,4vh,40px);padding-top:clamp(24px,5vh,48px);
  }
  .hero-copy{align-items:center;text-align:center}
  .hero h1{max-width:16ch}
  .hero .meta{justify-content:center}
  .shot{
    align-self:auto;justify-self:center;
    width:min(300px,64vw);margin-bottom:0;
  }
}

/* ONE studio mark, on every page and in the tab: assets/icons/bmlabs.png, the file the
   favicon already loads. It was drawn in CSS before — a "bm" glyph on a square mixed from
   `--ac` — which made BM Labs blue on the hub, orange on Kehribar and teal on Tern, and none
   of the three the icon. The PNG carries its own black squircle and white letters, so nothing
   here paints a background or a border: doing either would square off its corners. */
.mark{flex:none}

/* ---------------- home page ---------------- */

.nav .mark{width:30px;height:30px}

.home-hero{
  position:relative;overflow-x:clip;text-align:center;
  display:flex;flex-direction:column;align-items:center;
  padding:clamp(18px,3vh,48px) clamp(20px,5vw,32px) clamp(14px,2vh,24px);
}
.home-hero::before{
  /* Same as the app hero's: it starts above the nav, so the header sits inside the light instead
     of on a line drawn under it. */
  content:"";position:absolute;top:calc(-1 * var(--nav-h) - 240px);left:50%;transform:translateX(-50%);
  width:min(1100px,150%);aspect-ratio:1.4;pointer-events:none;
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--ac) var(--glow),transparent), transparent 72%);
}
.home-hero > *{position:relative;z-index:1}
.home-hero h1{
  font-size:clamp(36px,5.4vw,60px);font-weight:800;
  line-height:1.02;letter-spacing:-.045em;max-width:16ch;margin-bottom:12px;
}
.home-hero .lede{
  font-size:clamp(16.5px,1.7vw,19px);color:var(--fg-2);line-height:1.55;max-width:58ch;
}

.grid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px;
  padding-bottom:clamp(38px,6vh,60px);
}
.cell{
  --cell-ac:var(--ac);
  /* Accent text on a tinted surface fails contrast at 12px in light mode, so the accent is
     pulled toward the page's own foreground. It keeps its hue and gains the ratio. */
  --cell-ink:color-mix(in srgb,var(--cell-ac) 55%,var(--fg));
  display:flex;flex-direction:column;align-items:flex-start;
  padding:20px;border-radius:16px;border:1px solid var(--line);
  background:color-mix(in srgb,var(--cell-ac) 6%,var(--bg));
  transition:transform .22s cubic-bezier(.22,1,.36,1),box-shadow .22s;
  /* Every cell carries `id="<slug>-card"`, and three live apps use `/#<slug>-card` as their
     App Store marketing URL — so this id is somewhere a visitor ARRIVES, not just a hook the
     grid happens to have. The nav is a sticky capsule, so an un-margined landing puts the card
     the store sent them to underneath it. The offset is the capsule plus the air above it,
     which is already one token, plus a little so the card does not touch the bar. */
  scroll-margin-top:calc(var(--nav-h) + 14px);
}
.cell:hover{transform:translateY(-4px);box-shadow:0 20px 44px -26px rgba(10,12,15,.55)}
.cell img{width:56px;height:56px;margin-bottom:10px;
  filter:drop-shadow(0 8px 14px rgba(10,12,15,.45))}
.cell b{font-size:16px;font-weight:600}
.cell .cat{font-size:13px;color:var(--fg-3);margin-top:2px;margin-bottom:12px}
.badge{
  display:inline-flex;align-items:center;gap:6px;margin-top:auto;
  border-radius:99px;padding:5px 11px;font-size:12px;font-weight:600;
  background:var(--bg-2);color:var(--fg-2);
}
.badge svg{width:12px;height:12px;fill:currentColor}
.badge-store{background:color-mix(in srgb,var(--cell-ac) 12%,transparent);color:var(--cell-ink)}

/* Three columns since the fourth value was dropped (build-site.py → VALUES). Four items fell to
   2×2 at 860px; three would leave an orphan there, so the band stacks in one go instead. */
.values{
  list-style:none;display:grid;grid-template-columns:repeat(3,1fr);gap:22px 26px;
  border-top:1px solid var(--line);padding:26px 0 clamp(44px,7vh,72px);
}
.values li{display:flex;gap:11px}
.values svg{width:17px;height:17px;flex:0 0 auto;margin-top:3px;
  fill:none;stroke:var(--ac);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.values b{display:block;font-size:14.5px;font-weight:600}
.values p{font-size:13.5px;color:var(--fg-3);line-height:1.45;margin-top:3px}
@media(max-width:860px){.values{grid-template-columns:1fr}}

/* ---------------- footer ---------------- */
.foot{border-top:1px solid var(--line);background:var(--bg-2);padding:28px 0 44px}
.foot-in{display:flex;flex-wrap:wrap;gap:14px 26px;align-items:center;justify-content:space-between}
.foot a,.foot span{font-size:13.5px;color:var(--fg-3)}
.foot a:hover{color:var(--fg)}
.foot-links{display:flex;flex-wrap:wrap;gap:20px}
/* The studio line sits under the wordmark, so the brand is one two-line block and the links and
   the copyright keep the places they already had. */
.foot-brand{display:flex;flex-direction:column;gap:5px}
.foot-note{font-size:13px;color:var(--fg-3)}
.foot .home{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--fg-2);font-size:14px}
.foot .home .mark{width:24px;height:24px}

@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
