/* fs.css — the field in the hero, and the fullscreen it opens into.
 *
 * The interaction is one idea: the page gets out of the way and the field
 * takes the room. Headline and lede leave to the left, the meta row and the
 * closing line to the right, the header up, the footer down — and the input
 * you touched grows into the space they left.
 *
 * The growth is a clip-path travelling from the field's own rectangle to
 * the viewport edges. Not a transform: a scaled box distorts its own text
 * and its border thickness on the way, which is the cheap-modal look this
 * is trying not to have. Clipping moves an edge and leaves the content
 * alone, and it composites, so it stays smooth on a phone.
 */

/* ── the language switch, plain text like carta.vision ─────── */

.lang { display: inline-flex; gap: 0.5rem; font-family: var(--mono);
        font-size: 0.8rem; letter-spacing: 0.02em; }
.lang button {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--dim); font: inherit;
  transition: color 0.2s ease;
}
.lang button:hover { color: var(--fg); }
.lang button.on { color: var(--fg); }

/* A hairline between the three, so de/en/中文 reads as one control rather
   than three loose words. On the last one it would be a stray mark. */
.lang button + button { padding-left: 0.5rem; position: relative; }
.lang button + button::before {
  content: ""; position: absolute; left: 0; top: 0.2em; bottom: 0.2em;
  width: 1px; background: currentColor; opacity: 0.28;
}

/* ── the one claim that carries the whole page ─────────────── */

/* The point of this project is not that it is small — plenty of small
   models exist. It is WHERE it runs. So the CPU sentence is the only thing
   in the lede allowed to be as bright as the headline, and the third meta
   figure gets the accent the two measured numbers do not. */
.lede strong {
  color: var(--fg);
  font-weight: 620;
  /* The underline sits below the text rather than through the descenders,
     and it is the accent colour at low alpha — an actual rule, not a
     browser default text-decoration that would thicken with the font. */
  box-shadow: inset 0 -0.42em 0 rgba(215, 255, 62, 0.14);
}

/* ── the values ────────────────────────────────────────────── */

/* This replaced three figures in the hero — 1.95 %, 0 gradients, CPU. They
   were the shape of a product page's feature strip, and a number with a
   one-line caption cannot say WHY it matters. The claim that carries the
   project now lives in the lede, in a sentence, where it can be argued
   with. */
.values-title {
  font-size: clamp(1.75rem, 4.2vw, 3.25rem);
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-weight: 660;
  margin-bottom: clamp(2.5rem, 6vh, 4.5rem);
  max-width: 20ch;
}

.value-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, 4vw, 3.5rem) clamp(2rem, 5vw, 5rem);
}
@media (max-width: 780px) { .value-list { grid-template-columns: 1fr; } }

.value-list li {
  border-top: 1px solid var(--faint);
  padding-top: clamp(1rem, 2vw, 1.5rem);
}
.value-list h3 {
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  font-weight: 620;
  letter-spacing: -0.015em;
  margin-bottom: 0.6rem;
}
/* The rule above each value picks up the accent as it arrives, so the four
   read as one set being counted off rather than four separate boxes. */
.value-list li.in { border-top-color: rgba(215, 255, 62, 0.45); }
.value-list li { transition: border-top-color 0.8s ease 0.2s; }
.value-list p {
  color: var(--dim);
  font-size: clamp(0.92rem, 1.15vw, 1.05rem);
  line-height: 1.62;
  max-width: 46ch;
}

/* ── the hero, and clearing the header ─────────────────────── */

/* The header is position:fixed, so it takes no space in the flow and the
   hero has no idea it is there. Measured in an 829 px window: the headline
   started 16 px under it, and the hero was 856 px tall inside 829 — the
   global section rule pads 9vh top AND bottom, which at that height is
   150 px of padding around 706 px of content. Over budget, so centring had
   nothing left to centre with and the whole block sat jammed against the
   header.

   So the top padding clears the header explicitly and the bottom is the
   only free space. The headline is already bounded by 12.5vh, so the
   content shrinks with the window and this stays solvable on a short
   screen. */
:root { --nav-h: 3.75rem; }

.hero {
  padding-top: calc(var(--nav-h) + clamp(0.75rem, 3vh, 2.25rem));
  padding-bottom: clamp(1.5rem, 4.5vh, 3.5rem);
}

/* Six things stack in the hero — three headline lines, the lede, the field,
   its note and the meta row — and on a laptop they came to 706 px inside
   the 769 px left under the header. It fitted, with 26 px above and 12 px
   below, which is not spacing but a coincidence.

   The headline is already bounded by viewport height; this tightens that
   bound and the gaps between the blocks on short windows, so there is slack
   for justify-content to centre with. Nothing changes on a tall screen,
   where there was never a problem. */
@media (max-height: 900px) {
  .hero h1   { font-size: clamp(2.5rem, min(8.6vw, 11vh), 7.5rem); }
  .hero-talk { margin-top: clamp(1.25rem, 3.5vh, 2.5rem); }
  .talk-note { margin-top: 0.6rem; }
}

/* On a phone the headline drops to about 40 px and the whole hero shrinks
   to roughly half the screen, so it floats in the middle with the header
   hanging over it. More room above pushes the block down clear of the
   header and gives the top of the page somewhere to breathe — and there is
   height to spare here, which is exactly what there was not on a laptop. */
@media (max-width: 640px) {
  .hero {
    padding-top: calc(var(--nav-h) + clamp(2.5rem, 9vh, 5rem));
    padding-bottom: clamp(2rem, 6vh, 4rem);
  }
  .hero-talk { margin-top: clamp(1.5rem, 4vh, 2.5rem); }
}

/* ── the field in the hero ─────────────────────────────────── */

/* Full layout width: the field is the one thing on the page a visitor is
   meant to reach for, and a 42rem box under a 9rem headline reads as a
   footnote to it rather than the point of it. */
.hero-talk { margin: clamp(2rem, 5vh, 3.25rem) 0 0; width: 100%; }

.talk-field {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  padding: 1.05rem 1.25rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--faint);
  /* Rounded, not a pill: a pill at full width reads as a button, and this
     is a place to type. */
  border-radius: 10px;
  color: var(--dim);
  font: inherit;
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  text-align: left;
  cursor: text;
  white-space: nowrap;
  overflow: hidden;
  transition: border-color 0.3s ease, background 0.3s ease, color 0.3s ease;
}
.talk-field:hover, .talk-field:focus-visible {
  border-color: var(--accent);
  background: rgba(215, 255, 62, 0.04);
  color: var(--fg);
  outline: none;
}
.talk-caret {
  width: 2px; height: 1.15em; background: var(--accent); flex: 0 0 auto;
  animation: caret 1.15s steps(1) infinite;
}
@keyframes caret { 50% { opacity: 0; } }
.talk-hint { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.talk-go { font-family: var(--mono); font-size: 0.9rem; color: var(--accent); opacity: 0.6; }
.talk-note { margin: 0.85rem 0 0; font-size: 0.85rem; color: var(--dim); line-height: 1.6; }

/* ── the page stepping aside ───────────────────────────────── */

[data-exit] {
  transition: transform 0.55s cubic-bezier(0.65, 0, 0.35, 1),
              opacity 0.35s ease;
  will-change: transform;
}
/* !important, deliberately, and the reason is exact. landing.css pins a
   revealed element with

       .reveal.in:not(h1):not(h2) { opacity: 1; transform: none; }

   whose two :not() arguments push it to 0,2,2 — just above the 0,2,1 of
   `body.fs-open [data-exit]`. So without this the headline and the closing
   line left the screen (they are excluded by the :not) and the lede and the
   meta row sat exactly where they were. Measured, not guessed.

   Out-specifying it would mean a selector that breaks the next time someone
   renames a class. This is a transient state overriding a resting one,
   which is the case !important is actually for. */
body.fs-open [data-exit="left"]  { transform: translateX(-115vw) !important; opacity: 0; }
body.fs-open [data-exit="right"] { transform: translateX(115vw)  !important; opacity: 0; }
body.fs-open [data-exit="up"]    { transform: translateY(-120%)  !important; opacity: 0; }
body.fs-open [data-exit="down"]  { transform: translateY(120%)   !important; opacity: 0; }
body.fs-open .talk-field { opacity: 0; transition: opacity 0.2s ease; }

@media (prefers-reduced-motion: reduce) {
  [data-exit] { transition: opacity 0.2s ease; }
  body.fs-open [data-exit] { transform: none; }
}

/* ── the fullscreen ────────────────────────────────────────── */

.fs-wrap {
  position: fixed;
  inset: 0;
  z-index: 200;
  clip-path: inset(50% 50% 50% 50% round 10px);
  visibility: hidden;
  transition: clip-path 0.6s cubic-bezier(0.16, 1, 0.3, 1),
              visibility 0s linear 0.6s;
}
.fs-wrap.open {
  clip-path: inset(0 0 0 0 round 0);
  visibility: visible;
  transition: clip-path 0.6s cubic-bezier(0.16, 1, 0.3, 1), visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
  .fs-wrap, .fs-wrap.open { transition: visibility 0s; }
}

.fs {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: #000;
  background-image: radial-gradient(120% 80% at 50% 0%,
                    rgba(215, 255, 62, 0.05), transparent 60%);
}

/* WHY THE TYPE IS BIGGER IN HERE THAN ANYWHERE ELSE ON THE PAGE
   On the landing page this text sits next to a 9 rem headline, and body
   size is right because the headline sets the scale. In the fullscreen
   there IS no headline: the content is the entire screen, and the same
   0.9 rem reads as tiny lost in 1500 px of black.

   So the overlay gets its own root size that follows the viewport, and
   everything below is expressed in em against it — one number to move
   instead of fifteen. The ch-based measures come along for free: at a
   larger root, 70ch is a physically wider column, which is the whole
   point. */
/* 1.5vw, not the 1.15vw this first got: on a 1500 px screen that came out
   at 1.08rem — a rounding error away from the body size it was meant to
   escape. 1.5vw is ~22 px there, and the clamp keeps a phone at 1.1rem and
   a 4K screen from turning into a picture book. */
.fs { font-size: clamp(1.1rem, 1.5vw, 1.7rem); }

.fs-top {
  display: flex; align-items: center; gap: 1rem;
  padding: 1rem clamp(1rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--faint);
  flex: 0 0 auto;
}
.fs-top .mark { flex: 0 0 auto; font-size: 0.86em; }

/* There used to be two tabs here. The second one served the Wikipedia
   model, which reaches 3.99 bits a piece against roughly 2 for fluent
   German — about sixteen plausible continuations at every position, which
   is why it produced real words, real punctuation and no sentences. That
   is a measurement, and it belongs in the research record rather than on a
   page as a feature. What is left is a label, because with one thing in
   here a tab strip is a control with nothing to control. */
.fs-what {
  margin: 0 auto;
  font-family: var(--mono);
  font-size: 0.78em;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
}
.fs-close {
  background: none; border: none; color: var(--dim); font-size: 1.45em;
  cursor: pointer; padding: 0.2rem 0.4rem; line-height: 1; flex: 0 0 auto;
  transition: color 0.25s ease, transform 0.25s ease;
}
.fs-close:hover { color: var(--fg); transform: rotate(90deg); }

/* These are <section> and <header> elements, and the page styles those
   globally: section { display:flex; align-items:center; min-height:100svh;
   padding: ... }. Inside the fullscreen that centred every pane and left
   the header 392 px wide in a 1502 px window. Reset explicitly rather than
   rename the elements — a chat log IS a section, and the markup should say
   so. */
.fs-top, .fs-pane {
  align-items: stretch;
  min-height: 0;
  padding-block: 0;
  padding-inline: 0;
}
.fs-top { align-items: center; padding: 0.9em clamp(1.25rem, 5vw, 4rem); }
.fs-pane { display: none; flex: 1 1 auto; flex-direction: column; }
.fs-pane.is-on { display: flex; }

/* Full screen means full screen: the panes use the whole width and only
   the page's own gutter holds them off the edge. */
.chat-log, .chat-bar, .fs-foot {
  width: 100%;
  padding-inline: clamp(1.25rem, 5vw, 4rem);
}

.chat-log {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding-block: 2rem;
  display: flex; flex-direction: column; gap: 1em;
  scroll-behavior: smooth;
}
.msg {
  max-width: min(60ch, 76%);
  padding: 0.7em 1em;
  border-radius: 0.7em;
  line-height: 1.55;
  animation: msg-in 0.3s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes msg-in { from { opacity: 0; transform: translateY(8px); } }
.msg.you { align-self: flex-end; background: var(--accent); color: #000;
           border-bottom-right-radius: 0.2em; }
.msg.it  { align-self: flex-start; background: rgba(255, 255, 255, 0.07);
           border-bottom-left-radius: 0.2em; }
.msg.sys { align-self: center; background: none; color: var(--dim);
           font-family: var(--mono); font-size: 0.78em; max-width: 100%;
           text-align: center; }
.msg.it.pending { color: var(--dim); font-style: italic; }

.chat-bar { display: flex; gap: 0.6em; padding-block: 1rem 0; flex: 0 0 auto; }
.chat-bar input {
  flex: 1; min-width: 0;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--faint);
  border-radius: 0.55em;
  color: var(--fg);
  padding: 0.75em 0.95em;
  font: inherit;
  /* iOS Safari zooms the whole page when it focuses a field set below 16
     CSS pixels, and does not zoom back out afterwards — you tap the input
     and the layout is left magnified. Inheriting .fs put this at 16.32 px
     on a phone, which clears the threshold by a third of a pixel and only
     as long as nobody's root size is under 16.

     max() removes the question instead of winning it narrowly: never below
     16 px whatever the root is, and still scaling with the overlay on a
     desktop. Deliberately NOT solved with maximum-scale=1 in the viewport
     meta, which stops the zoom by taking pinch-zoom away from everyone. */
  font-size: max(16px, 1em);
}
.chat-bar input:focus { outline: none; border-color: var(--accent); }
.chat-bar input::placeholder { color: var(--dim); }

/* landing.css gives .btn a 0.72rem uppercase mono label in a 999px pill.
   That is right for a small control tucked under a demo panel. Next to a
   22px input it renders as a tiny circle with the word squeezed inside —
   the send button ends up the least legible thing on a screen that exists
   to be typed into. So in here it matches the input: same height, same
   corner, and the accent, because it IS the action. */
.chat-bar .btn {
  flex: 0 0 auto;
  font-family: inherit;
  font-size: 0.92em;
  letter-spacing: 0;
  text-transform: none;
  padding: 0.75em 1.6em;
  border-radius: 0.55em;
  background: var(--accent);
  border-color: var(--accent);
  color: #000;
  font-weight: 560;
}
.chat-bar .btn:hover:not([disabled]) { filter: brightness(1.08); }
.chat-bar .btn[disabled] { opacity: 0.32; cursor: default; }

.fs-foot {
  display: flex; justify-content: space-between; gap: 1rem;
  padding-block: 0.7rem 1.3rem;
  font-family: var(--mono); font-size: 0.76em; color: var(--dim);
  flex: 0 0 auto;
}
/* Which brain answered this session, and its current numbers -- read from
   /api/public/chat/state (fs.js's renderBrainLine). Sits right under the
   status/clear row, quieter than it: this is provenance, not status. */
.fs-brainline {
  width: 100%;
  padding-inline: clamp(1.25rem, 5vw, 4rem);
  padding-block: 0 1rem;
  font-family: var(--mono); font-size: 0.68em; color: var(--faint);
  flex: 0 0 auto;
}
.fs-brainline:empty { display: none; }
.linkish {
  background: none; border: none; color: var(--dim); font: inherit;
  cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}
.linkish:hover { color: var(--fg); }

/* position:fixed, not overflow:hidden alone. The overlay opens over a page
   that is still scrollable underneath it in iOS Safari, and `overflow:
   hidden` on the body does not remember where the reader was — fs.js pins
   the offset with a matching negative top and hands it back on close. */
body.fs-open {
  overflow: hidden;
  position: fixed;
  width: 100%;
}

/* Scrolling the chat log must stop at the chat log. Without this the
   overscroll chains to the page behind, which on a phone is how you close
   an overlay you were only trying to read. */
.chat-log { overscroll-behavior: contain; }

@media (max-width: 640px) {
  .fs-what { display: none; }
  .msg { max-width: 92%; }
  .fs { font-size: 1.05rem; }
}
