/* THE WAY IN — the page a returning creator lands on.
 *
 * It shares the studio's ink (css/app.css) on purpose: the same navy, the same accent, the same
 * line colour, so arriving in the studio is a continuation and not a different product. What it
 * does NOT share is density. The studio is an instrument and is allowed to be busy; this page
 * asks one question, so everything that is not that question is quiet, far apart, and dim.
 */

:root {
  --bg:          #05070f;
  --bg-2:        #0b0e1d;
  --panel:       #101530;
  --panel-2:     #161c3c;
  --line:        #212a4e;
  --line-2:      #2d3866;
  --text:        #e9edfb;
  --text-2:      #9aa5cc;
  --text-3:      #7883ac;
  --accent:      #5b8cff;
  --accent-2:    #8ab4ff;
  --accent-ink:  #eef3ff;
  --r:           14px;
  --rail-w:      268px;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 15px/1.55 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Inter, Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

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

/* ── the sky ───────────────────────────────────────────────────────────────
 *
 * THE PLANET IS A PHOTOGRAPH NOW, not a drawing of one. The rim, the sun clearing the limb and
 * the nebula were all being drawn in canvas — three strokes of falling width, a radial hot spot,
 * a gradient body — and it was a good imitation that still read as an imitation. The real plate
 * is 30 KB.
 *
 * IT IS A CSS BACKGROUND AND NOT A PER-FRAME BLIT. Painting a 1672x941 image into the canvas on
 * every frame is a full-screen copy sixty times a second to show something that never changes;
 * as a background the browser uploads it once. What is left on the canvas is the part that is
 * actually alive.
 *
 * `center top` with `cover` is load-bearing, not a default: js/start/sky.js solves the same
 * transform to find where the lit rim landed, so the vapour lifts off the edge in the photograph
 * instead of off a guess. Change one and the other has to change with it. */
#sky-photo {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background: var(--bg, #05070f) url("/assets/moon.webp") center top / cover no-repeat;
}
/* THE SAME PLATE, STILL HAPPENING. It lies exactly over #sky-photo and shows the same picture,
   so the hand-off is invisible: it is revealed only after its first frame is drawn, and if it
   never arrives — no WebGL, a lost context, reduced motion — the still plate underneath is what
   stays on screen, which is a complete picture and not a fallback anybody would notice. */
#sky-live {
  position: fixed; inset: 0; width: 100%; height: 100%;
  display: block; z-index: 1; pointer-events: none;
  opacity: 0; transition: opacity .9s ease;
}
#sky-live.on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { #sky-live { display: none; } }

#sky {
  position: fixed; inset: 0; width: 100%; height: 100%;
  display: block; z-index: 2; pointer-events: none;
}
/* Pulls the corners down so the headline sits on black rather than on the haze. */
.vignette {
  position: fixed; inset: 0; z-index: 3; pointer-events: none;
  background:
    radial-gradient(130% 95% at 50% 42%, transparent 38%, rgba(3,5,12,.55) 76%, rgba(3,5,12,.92) 100%);
}

/* ── the rail ────────────────────────────────────────────────────────────── */
#rail {
  position: fixed; z-index: 6; inset: 0 auto 0 0;
  width: var(--rail-w); padding: 18px 12px 14px;
  display: flex; flex-direction: column; gap: 12px;
  background: linear-gradient(to right, rgba(5,7,15,.92), rgba(5,7,15,.62) 72%, transparent);
  transition: transform .34s cubic-bezier(.4,0,.2,1), opacity .24s ease;
}
body.rail-closed #rail { transform: translateX(calc(-1 * var(--rail-w))); opacity: 0; }

.rail-head { display: flex; align-items: center; gap: 10px; padding: 0 6px 2px; }
.brand { display: flex; align-items: center; gap: 9px; text-decoration: none; color: var(--text); }
/* THE LOGO, not a square standing in for it. The glow stays — it is what makes the mark sit on
   a night sky rather than on top of it — but it is thrown by the artwork now. */
.brand .mark {
  width: 18px; height: 18px; display: block;
  object-fit: contain;
  filter: drop-shadow(0 0 12px rgba(91,140,255,.55));
}
.brand-name { font-size: 14.5px; font-weight: 600; letter-spacing: .14em; }
.brand-name i { font-style: normal; color: var(--text-3); margin-left: 4px; font-weight: 500; }

.rail-icon {
  margin-left: auto; width: 28px; height: 28px; display: grid; place-items: center;
  background: transparent; border: 0; border-radius: 8px; color: var(--text-3); cursor: pointer;
}
.rail-icon:hover { color: var(--text); background: rgba(255,255,255,.05); }

.rail-new {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 10px 12px; cursor: pointer;
  background: linear-gradient(180deg, rgba(91,140,255,.19), rgba(91,140,255,.09));
  border: 1px solid rgba(91,140,255,.34); border-radius: 11px;
  color: var(--accent-ink); font: inherit; font-size: 13.5px; font-weight: 550;
  transition: border-color .16s ease, background .16s ease, transform .1s ease;
}
.rail-new:hover { border-color: rgba(91,140,255,.6); background: linear-gradient(180deg, rgba(91,140,255,.26), rgba(91,140,255,.12)); }
.rail-new:active { transform: translateY(1px); }

.rail-find {
  display: flex; align-items: center; gap: 8px; padding: 0 10px; height: 34px;
  background: rgba(255,255,255,.035); border: 1px solid var(--line); border-radius: 10px;
  color: var(--text-3);
}
.rail-find input {
  flex: 1; min-width: 0; background: transparent; border: 0; outline: none;
  color: var(--text); font: inherit; font-size: 13px;
}
.rail-find input::placeholder { color: var(--text-3); }

.rail-list { flex: 1; min-height: 0; overflow: auto; margin: 2px -4px 0; padding: 0 4px; }
/* ONE LIST, so there are no group headings left. See loadRail() in js/start/start.js: a
   conversation IS a project, which is the rule the studio is built on, and splitting the same
   work into "Worlds" and "Conversations" on the way in contradicted it on the first screen.

   THE ROW IS THE STUDIO'S ROW. Same two lines, same order, same words: the name, then what is
   in there and when it was last touched. Set beside the drawer inside the studio they read as
   one list in two places, which is what they are. */
.rail-item {
  display: flex; flex-direction: column; gap: 1px;
  width: 100%; text-align: left; cursor: pointer;
  padding: 7px 10px; margin-bottom: 1px;
  background: transparent; border: 0; border-radius: 9px;
  color: var(--text-2); font: inherit;
  transition: background .13s ease, color .13s ease;
}
.rail-item:hover { background: rgba(255,255,255,.055); color: var(--text); }
.ri-name {
  font-size: 12.5px; font-weight: 500; line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ri-meta {
  display: flex; align-items: baseline; gap: 6px;
  font-size: 10.5px; line-height: 1.3; color: var(--text-3);
  overflow: hidden; white-space: nowrap;
}
.ri-meta i { font-style: normal; flex: 0 0 auto; margin-left: auto; }
.rail-empty { padding: 18px 10px; color: var(--text-3); font-size: 12.5px; line-height: 1.5; }

/* WHO IS SIGNED IN, built like the account chip in the studio's top bar: the same disc, the
   same initial, the name on top and the quiet line under it. It is one target that opens the
   studio rather than a label with a link parked beside it. */
.rail-foot { padding: 6px 6px 0; border-top: 1px solid var(--line); }
.rail-who {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 7px; border-radius: 10px;
  color: var(--text-2); text-decoration: none;
  transition: background .13s ease;
}
.rail-who:hover { background: rgba(255,255,255,.055); }
.rail-who .av {
  flex: 0 0 auto;
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: linear-gradient(145deg, var(--accent-2), var(--accent));
  color: #081028; font-size: 12px; font-weight: 700;
}
.who-text { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.who-text b {
  font-size: 12.5px; font-weight: 550; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.who-text i {
  font-style: normal; font-size: 10.5px; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* `rail-show`, AND THE NAME IS THE FIX.
 *
 * This button was class `rail-open`, and start.js puts `rail-open` ON THE BODY to mean "the rail
 * is out". So every rule written for a 36px floating button landed on <body>: the page became
 * `position: fixed`, 36 by 36, at 16,16, wearing the button's background — and because the rule
 * also carries `backdrop-filter`, body became the containing block for every `position: fixed`
 * child, so the rail and both sky layers collapsed into that square too. On a phone, one tap on
 * this button turned the whole product into a dark 36px tile. Measured: #sky-photo 34x34 at
 * (17,17), and nothing at all under the middle of the screen.
 *
 * A state on the body and a component in the page are different namespaces that CSS happens to
 * spell the same way, and this is the second time in this interface that a shared class name has
 * quietly handed one thing another thing's rules. The button is named for what it does. */
.rail-show {
  position: fixed; z-index: 7; top: 16px; left: 16px;
  width: 36px; height: 36px; display: none; place-items: center;
  background: rgba(10,14,28,.7); border: 1px solid var(--line); border-radius: 10px;
  color: var(--text-2); cursor: pointer; backdrop-filter: blur(10px);
}
body.rail-closed .rail-show { display: grid; }
.rail-show:hover { color: var(--text); border-color: var(--line-2); }

/* ── the ask ─────────────────────────────────────────────────────────────── */
#stage {
  position: relative; z-index: 4; height: 100%;
  display: grid; place-items: center;
  padding: 40px 28px 56px calc(var(--rail-w) + 28px);
  transition: padding .34s cubic-bezier(.4,0,.2,1), opacity .4s ease, transform .4s ease;
}
body.rail-closed #stage { padding-left: 28px; }
body.building #stage { opacity: 0; transform: scale(.985); pointer-events: none; }

.centre { width: min(960px, 100%); text-align: center; }

.wordmark {
  margin: 0 0 30px; font-size: 14px; font-weight: 500;
  letter-spacing: .42em; color: var(--text); text-transform: none;
}
.wordmark span { color: var(--text-3); margin-left: 2px; }

.head {
  margin: 0 0 22px; font-weight: 300; letter-spacing: -.016em;
  font-size: clamp(30px, 5.1vw, 62px); line-height: 1.12; color: #fff;
}
.head span { display: block; }

.sub {
  margin: 0 auto 38px; max-width: 760px;
  font-size: clamp(14px, 1.35vw, 17px); line-height: 1.62; color: var(--text-2);
}

/* The bar. One ring, lit from inside — the only lit object on the page, because it is the only
   thing being asked for. */
#ask { max-width: 960px; margin: 0 auto; }
.ask-shell {
  position: relative; display: flex; align-items: center; gap: 12px;
  padding: 11px 11px 11px 13px;
  background: linear-gradient(180deg, rgba(17,23,46,.86), rgba(10,14,30,.9));
  border: 1px solid rgba(91,140,255,.3); border-radius: 18px;
  box-shadow: 0 0 0 1px rgba(91,140,255,.07), 0 22px 60px -26px rgba(0,0,0,.95),
              0 0 70px -28px rgba(91,140,255,.55);
  transition: border-color .2s ease, box-shadow .25s ease;
}
.ask-shell:focus-within {
  border-color: rgba(91,140,255,.62);
  box-shadow: 0 0 0 1px rgba(91,140,255,.16), 0 22px 60px -24px rgba(0,0,0,.95),
              0 0 92px -24px rgba(91,140,255,.75);
}
body.dragging .ask-shell { border-color: rgba(138,180,255,.8); }

.ask-plus {
  flex: none; width: 42px; height: 42px; display: grid; place-items: center;
  background: rgba(91,140,255,.1); border: 1px solid rgba(91,140,255,.26);
  border-radius: 12px; color: var(--accent-2); cursor: pointer;
  transition: background .16s ease, color .16s ease, border-color .16s ease;
}
.ask-plus:hover { background: rgba(91,140,255,.2); color: #fff; border-color: rgba(91,140,255,.5); }
.ask-rule { flex: none; width: 1px; height: 24px; background: var(--line-2); }

#ask-input {
  flex: 1; min-width: 0; resize: none; max-height: 168px; min-height: 42px;
  padding: 9px 2px; background: transparent; border: 0; outline: none;
  color: var(--text); font: inherit; font-size: 15px; line-height: 1.5;
}
#ask-input::placeholder { color: var(--text-3); }

.ask-go {
  flex: none; width: 42px; height: 42px; display: grid; place-items: center;
  background: linear-gradient(160deg, var(--accent-2), var(--accent));
  border: 0; border-radius: 12px; color: #071027; cursor: pointer;
  box-shadow: 0 6px 20px -8px rgba(91,140,255,.9);
  transition: filter .16s ease, transform .1s ease;
}
.ask-go:hover { filter: brightness(1.1); }
.ask-go:active { transform: translateY(1px); }
.ask-go { position: relative; }
.ask-go .go-arrow { display: none; }

/* WHILE IT IS LISTENING. The button is already the loudest thing on the page, so this does not
   shout — it breathes, which is the only honest way to say "this is on" without a word of text:
   something that moves is something that is running. */
.ask-go .go-live {
  position: absolute; inset: -5px; border-radius: 16px; pointer-events: none;
  border: 2px solid rgba(167,139,250,.85); opacity: 0;
}
body.voice-live .ask-go .go-live { animation: go-breathe 1.4s ease-in-out infinite; }
body.voice-live .ask-go { filter: brightness(1.08); }
@keyframes go-breathe {
  0%, 100% { opacity: .3; transform: scale(1); }
  50%      { opacity: .95; transform: scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  body.voice-live .ask-go .go-live { animation: none; opacity: .85; }
}

/* WHAT IT IS DOING, IN WORDS, under the box — because a pulsing ring says something is happening
   and not what. It is one short line and it goes away again. */
.voice-note {
  margin: 10px auto 0; max-width: 960px; text-align: center;
  font-size: 12.5px; line-height: 1.5; color: var(--text-3); min-height: 18px;
}
.voice-note.bad { color: #ff9db0; }
body.has-ask .ask-go .go-wave { display: none; }
body.has-ask .ask-go .go-arrow { display: block; }

.ask-drop {
  margin-top: 12px; padding: 13px; border: 1px dashed var(--line-2); border-radius: 12px;
  color: var(--text-3); font-size: 13px;
}
body.dragging .ask-drop { border-color: var(--accent); color: var(--accent-2); }

.ask-files { list-style: none; display: flex; flex-wrap: wrap; gap: 7px; margin: 12px 0 0; padding: 0; justify-content: center; }
.ask-files li {
  display: flex; align-items: center; gap: 7px; padding: 5px 9px;
  background: rgba(255,255,255,.05); border: 1px solid var(--line); border-radius: 9px;
  color: var(--text-2); font-size: 12.2px;
}
.ask-files button { background: 0; border: 0; color: var(--text-3); cursor: pointer; padding: 0 1px; font-size: 14px; line-height: 1; }
.ask-files button:hover { color: #ff8da1; }

.kinds {
  list-style: none; display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 14px; margin: 40px 0 0; padding: 0;
}
.kinds .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--accent); opacity: .55; }
.kinds button {
  background: 0; border: 0; padding: 4px 2px; cursor: pointer;
  color: var(--text-3); font: inherit; font-size: 13px; letter-spacing: .055em;
  border-bottom: 1px solid transparent; transition: color .16s ease, border-color .16s ease;
}
.kinds button:hover { color: var(--text); }
.kinds button[aria-pressed="true"] { color: var(--accent-2); border-bottom-color: rgba(91,140,255,.55); }

/* ── building ────────────────────────────────────────────────────────────── */
/* `hidden` has to beat `display:flex`, or the build screen is on top of the ask from the first
   paint — which is exactly what it did. */
#building[hidden] { display: none !important; }
#building {
  position: fixed; inset: 0; z-index: 8;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0; padding: 40px 28px;
  opacity: 0; transform: scale(.99);
  animation: build-in .5s cubic-bezier(.2,0,.2,1) forwards;
}
@keyframes build-in { to { opacity: 1; transform: none; } }

.build-stage { width: min(760px, 86vw); aspect-ratio: 16 / 10; position: relative; }
.build-view { position: absolute; inset: 0; }
.build-view canvas { width: 100% !important; height: 100% !important; display: block; }

.build-head {
  margin: 26px 0 8px; font-weight: 300; letter-spacing: -.012em;
  font-size: clamp(24px, 3.3vw, 40px); color: #fff;
}
.build-head span#build-what { color: var(--accent-2); }
.build-head .ell { color: var(--text-3); }
.build-sub { margin: 0 0 30px; color: var(--text-2); font-size: clamp(13px, 1.2vw, 15.5px); }

.build-bar {
  width: min(620px, 78vw); height: 5px; border-radius: 999px;
  background: rgba(255,255,255,.08); overflow: hidden;
}
.build-bar i {
  display: block; width: 0; height: 100%; border-radius: inherit;
  background: linear-gradient(90deg, #2f5fd0, var(--accent) 48%, #cfe0ff);
  box-shadow: 0 0 18px -2px rgba(91,140,255,.85);
  transition: width .45s cubic-bezier(.3,0,.2,1);
}
.build-pct { margin: 11px 0 0; font-size: 13.5px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.build-step { margin: 5px 0 0; min-height: 17px; font-size: 12.5px; color: var(--text-3); }

.build-stop {
  margin-top: 24px; padding: 8px 18px; cursor: pointer;
  background: transparent; border: 1px solid var(--line-2); border-radius: 999px;
  color: var(--text-3); font: inherit; font-size: 12.5px;
  transition: color .15s ease, border-color .15s ease;
}
.build-stop:hover { color: #ff9db0; border-color: rgba(255,120,150,.5); }

/* ── narrower ────────────────────────────────────────────────────────────── */
@media (max-width: 1100px) {
  :root { --rail-w: 232px; }
}
/* ── ON A PHONE ────────────────────────────────────────────────────────────
 *
 * The desktop page put on a 390px screen was a page of text with the thing you came to do
 * pushed to the bottom of it: wordmark, two-line headline, a two-sentence paragraph, and only
 * then the box you type in — which landed 406px down a 664px screen, with the trades below it
 * at 524px, nearly off the bottom. Everything was legible and nothing was reachable.
 *
 * So on a phone the page says less. The wordmark goes, because the mark is already in the rail
 * and on the button. The paragraph goes, because the headline and the box's own placeholder
 * between them say the same thing in half the room. What is left is the one sentence that makes
 * the promise, the box, and the trades directly under it where a thumb is. */
@media (max-width: 860px) {
  #rail { transform: translateX(calc(-1 * var(--rail-w))); opacity: 0; }
  body.rail-open #rail { transform: none; opacity: 1; box-shadow: 0 0 80px rgba(0,0,0,.8); }
  .rail-show { display: grid; }
  /* The rail is a sheet over the page here, so the stage keeps the whole width underneath it. */
  #stage, body.rail-closed #stage { padding: 64px 20px 32px; }

  .wordmark { display: none; }
  .sub { display: none; }
  .head {
    margin: 0 0 20px; font-size: clamp(26px, 7.4vw, 34px); line-height: 1.16;
  }
  /* Two short lines read as one statement on a narrow screen; the desktop break lands wrong. */
  .head span { display: inline; }

  /* THE BOX HOLDS WHAT IT SAYS. At this width the prompt wraps to two lines whatever sensible
     words it is made of, and a one-line box showed the second line sliced through the middle —
     measured at 63px of text in a 42px opening. So the box opens to two lines here. It is also
     simply the right size to type a sentence into on a phone. */
  #ask-input { min-height: 60px; font-size: 14.5px; }
  .ask-shell { padding: 9px 9px 9px 11px; gap: 9px; align-items: flex-start; }
  .ask-plus, .ask-go { margin-top: 1px; }

  /* UP AGAINST THE BOX, not floated off the bottom of the screen. And laid out as a block of
     words rather than one centred stream, so the eye can take the six of them in at once. */
  .kinds { gap: 8px 14px; margin: 22px 0 0; }
  .kinds button { font-size: 12.5px; padding: 3px 2px; letter-spacing: .04em; }
  .kinds .dot { display: none; }
}

/* THE RAIL IS OUT WHEN THEY ARRIVE. What they came back for is the work they already have, and
   on a phone it was behind a button with no label. It opens on arrival and the arrow in its head
   closes it — and once closed, it stays closed, because start.js remembers the choice. */
@media (max-width: 860px) {
  body.rail-open #stage { pointer-events: none; }
  body.rail-open::after {
    content: ""; position: fixed; inset: 0; z-index: 5;
    background: rgba(3,5,12,.58); backdrop-filter: blur(1.5px);
  }
  #rail { z-index: 6; }

  /* A SHEET IS OPAQUE. The rail's own background fades out towards its right edge, which is
     right where it is a column standing on the sky and wrong where it is laid OVER the page:
     the headline and the ask box read straight through the list of conversations, and both
     became unreadable. Here it is a solid surface with an edge. */
  body.rail-open #rail {
    background: linear-gradient(to right, #04060d, #070a16);
    border-right: 1px solid var(--line);
  }

  /* AND THE BUTTON THAT OPENS IT GOES AWAY ONCE IT IS OPEN — it sat on top of the wordmark in
     the rail's own head, two controls in one 36px corner. */
  body.rail-open .rail-show { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
