/* ============================================================
   fofiy — the chrome, written once.

   `tokens.css` was already the single source for colour, type, space, radius
   and motion, and that stopped one class of drift: nothing on any surface
   invents a hex or an off-scale size. It did not stop the other class. Six
   pages each held their own copy of the *components* built out of those
   tokens — the shell, the app bar, the wordmark, the theme button, the
   language picker, the rail, the tab bar, the footer — and a component copied
   six ways drifts six ways, quietly, because each copy is correct on the day
   it is written.

   What that had already cost, measured rather than guessed: 316 distinct
   selectors across the six pages, of which 40 appeared on three or more.
   Twenty-seven were byte-identical — pure duplication waiting to diverge.
   Thirteen shared a name and disagreed:

     · `.brand svg` was 24 px on three pages and 26 px on the other three;
     · `.langs` wrote `999px` on two pages and `--r-pill` on four, which is the
       same number and the wrong habit — the token exists so the radius scale
       can move;
     · `.langs button` was `5px 10px` on three pages, `6px 12px` on two, and a
       `min-height` on the sixth;
     · `footer` padded `--s-5`, `--s-6` and `--s-7` on different pages.

   Nobody decided any of that. It is what happens to markup that is copied,
   and it is the same failure the language picker had: the six static pages
   collapsed it months ago, app.html did not, and nobody noticed until it was
   the first thing on the door.

   WHAT BELONGS HERE. Chrome — the parts that are the *same product* rather
   than the same page. If two surfaces should look different (Poudrose is
   photographic, Pacrea is a workspace, the legal pages are documents), the
   difference belongs in that page's own `<style>`, which loads after this and
   wins at equal specificity.

   WHAT DOES NOT. Anything editorial: headings, section rhythm, the wall, the
   retention figures, a page's own empty states. Those are the page.

   TWO LAYERS. Everything down to the footer applies to all six pages. The
   shell — rail, tab bar, app bar — applies to the three that have one
   (`home`, `poudrose`, `pacrea`); the legal pages and /about carry no such
   markup, so those rules simply match nothing there.

   ORDER. `tokens.css`, then this, then the page. Never the other way round.
   ============================================================ */

/* ---- the column ------------------------------------------- */
.wrap { width: 100%; max-width: 1180px; margin: 0 auto; padding-inline: var(--s-4) }
@media (min-width: 720px) { .wrap { padding-inline: var(--s-6) } }
/* `min-width: 0` with it. A flex item's default minimum is its content, so a
   long unbroken string in a `.grow` pushes the row wider than its container
   instead of ellipsing — which is why every one of app.html's twenty-one
   scoped copies of this rule carries both declarations. The two sheets say the
   same thing about this name on purpose; `test:css` counts it as the one
   deliberate convergence between the two shells. */
.grow { flex: 1; min-width: 0 }

/* ---- the wordmark ------------------------------------------
   THE LOGO IS THE WORDMARK, AND THE MARK IS ITS FIRST O. Four concentric
   circles standing in for the letter, and the tittle on the i in the same
   coral. Where only a mark will fit — a favicon, an app icon, an avatar — the
   ripple stands alone; it is the same drawing at the same proportions, never a
   cropped wordmark.

   The letters are INK and the ripple is the accent. The old wordmark was the
   accent all through, which put the loudest colour in the product on a control
   that is only ever "start again here" — and with a coral that reads as a
   warning when it is the whole word rather than one letter of it.

   `.wm` is one rule for every surface: the app bar, the gate, six static pages.
   The ripple is sized in em, so it follows whatever the wordmark is set in and
   there is no second size to keep in step. */
.brand { display: inline-flex; align-items: center; gap: var(--s-2); color: var(--ink);
  text-decoration: none; font: var(--t-title) }
/* Nothing here about how the logo is drawn. This set the display family (which
   `.wm` already owns) and −.02em of tracking, on the one element whose own rule
   in tokens.css says in as many words that negative tracking closes the gap
   between the f and the dotless i. A caller sizes the wordmark; it does not
   letter it. */

/* ---- theme ------------------------------------------------- */
.thm { border: 0; background: var(--surface-2); border-radius: var(--r-pill);
  width: 34px; height: 34px; display: grid; place-items: center; cursor: pointer;
  color: var(--ink-2); flex: 0 0 auto }
.thm:hover { color: var(--action) }
.thm .icon { width: 17px; height: 17px }

/* ---- language, collapsed -----------------------------------
   It shows the language that is on and opens on a press: two of three buttons
   are always wrong for whoever is reading, and they sat beside the wordmark in
   the best strip of the page. Opening is `theme.js`; nothing here knows what a
   language is.

   `:root` on the front of each selector, because tokens.css sets
   `display: inline-flex` on `.langs button` under a coarse pointer — at
   (0,2,1), which beats a bare `.langs button`. Without it the group stays open
   on a phone and closes correctly on a desktop, which is the one device
   nobody would have checked. And the shown button restores `inline-flex`
   rather than `block`, or it loses the centring that rule exists to give it. */
.langs { display: flex; gap: 2px; background: var(--surface-2);
  border-radius: var(--r-pill); padding: 3px }
.langs button { border: 0; background: none; border-radius: var(--r-pill);
  padding: 6px 12px; font: var(--t-caption); color: var(--ink-2); cursor: pointer }
.langs button[aria-current="true"] { background: var(--surface); color: var(--action) }
:root .langs button { display: none }
:root .langs button[aria-current="true"],
:root .langs[data-open] button {
  display: inline-flex; align-items: center; justify-content: center;
}
.langs[data-open] { box-shadow: inset 0 0 0 1px var(--line-strong) }

/* ---- footer ------------------------------------------------ */
footer { border-top: 1px solid var(--line); padding-block: var(--s-6);
  font: var(--t-caption); color: var(--ink-3) }
footer a { color: var(--ink-2); text-decoration: none }
footer a:hover { color: var(--action) }

/* ============================================================
   The shell — the three pages that have a rail and a tab bar.
   ============================================================ */

.shell { min-height: 100svh; display: flex; flex-direction: column }

.appbar { position: sticky; top: 0; z-index: 30; background: var(--bg);
  border-bottom: 1px solid var(--line) }
.appbar .wrap { display: flex; align-items: center; gap: var(--s-3);
  padding-block: var(--s-3) }

/* Declared before the media query, not after it: both selectors have the same
   specificity, so a later `display:none` wins at every width and the rail is
   dead on the desktop it exists for. It was, until this was measured. */
.rail { display: none }
.rail a { display: flex; align-items: center; gap: var(--s-3);
  padding: 10px var(--s-3); border-radius: var(--r-input); font: var(--t-body-md);
  color: var(--ink-2) }
.rail a:hover { background: var(--surface-2); color: var(--ink) }
.rail a[aria-current="page"] { background: var(--action-soft); color: var(--action-on-soft) }
.rail a .icon { color: currentColor }
.rail .brand { margin: 0 var(--s-3) var(--s-5) }
.rail hr { border: 0; border-top: 1px solid var(--line); margin: var(--s-3) var(--s-3) }

@media (min-width: 1080px) {
  .shell { flex-direction: row }
  .rail { width: 232px; flex: 0 0 auto; border-inline-end: 1px solid var(--line);
    padding: var(--s-5) var(--s-3); position: sticky; top: 0; height: 100svh;
    display: flex; flex-direction: column; gap: 2px }
  .col { flex: 1; min-width: 0; display: flex; flex-direction: column }
  .appbar { border-bottom: 0 }
  .appbar .brand { display: none }
  /* Scoped to the column rather than bare `main`: the legal pages have no
     `.col`, and a bare `main` here would reach across and rewrite their
     padding on desktop only — which is exactly the kind of thing that gets
     shipped, because nobody resizes a privacy policy. */
  .col main { padding-bottom: var(--s-8) }
}

/* ---- tab bar -----------------------------------------------
   Asking is the product's central act, so it is the middle tab and the one
   filled thing in the row — the same position and weight the app gives its own
   FAB, so the two bars read as one product. It never carries `aria-current`,
   because it is something you do rather than somewhere you are. */
.tabbar { position: fixed; inset-inline: 0; bottom: 0; z-index: 30;
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: var(--surface); border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom) }
.tabbar a { display: grid; place-items: center; gap: 2px; padding: 10px 4px;
  font: var(--t-micro); color: var(--ink-3) }
.tabbar a[aria-current="page"] { color: var(--action) }
.tabbar .icon { width: 21px; height: 21px }
.tabbar .ask-tab { color: var(--action) }
.tabbar .ask-tab .icon { width: 44px; height: 44px; padding: 11px;
  border-radius: var(--r-pill); background: var(--action-fill); color: var(--action-ink);
  box-shadow: var(--e-2) }
.tabbar .ask-tab span { color: var(--action) }
@media (min-width: 1080px) { .tabbar { display: none } }
