/* The site chrome: the top bar and the footer, everywhere they appear.
 *
 * **One source, two servers.** The marketing pages are static files served by
 * nginx; `yomita.ai/blogs/` is rendered by FastAPI and bypasses nginx entirely
 * (ADR 0012). Both used to carry their own header and footer, and `blog.css`
 * said so in its own opening comment — the brand tokens were "copied from
 * client/site/styles.css", a drift risk it named and could not fix from where
 * it sat. This file is the mechanism it was missing.
 *
 * Neither stack reads the other's routes. `tools/build-i18n.py` copies this
 * file to `client/site/chrome.css` for nginx, and `server/app/site/` serves the
 * copy in its own image at `/blogs/chrome.css`. The blog therefore still works
 * standing alone, which is what `blog.css` was protecting when it refused to
 * link `/styles.css`.
 *
 * Load it FIRST, before the page's own stylesheet: everything here is chrome
 * that a page is entitled to override, and none of it is written to win a
 * specificity fight.
 *
 * The markup that goes with it is `shared/web/header.html` and `footer.html`.
 * Change one without the other and both stacks are wrong at once — which is
 * the trade for having stopped them being wrong separately.
 */

/* --- brand tokens ---------------------------------------------------------
 * The colours and faces, which are the half both stylesheets had a copy of.
 * Layout variables stay with the stylesheet that lays something out: `--max`
 * is the marketing grid's, `--measure` is the blog's column, and neither has
 * any business in the other. */

:root {
  --bg: #ffffff;
  --ink: #16101f;
  --ink-2: #4a4457;
  --muted: #8b8398;
  --line: #ede9f0;
  --wash: #f8f5fa;

  /* Rose. The brand's accent, and the one colour on the page that is not the
     mark or a placeholder. */
  --accent: #de3b62;
  --accent-soft: rgb(222 59 98 / 14%);

  --amber: #f9c463;
  --violet: #6e42a6;

  /* The mark's own gradient, lifted from assets/mark.svg so the wordmark and
     the SVG cannot drift apart. The SVG runs it at 139° across a square; here
     it is shallower, because a wide short word needs the three stops spread
     along its length rather than crammed into its height. */
  --dusk: linear-gradient(115deg, var(--amber) 0%, var(--accent) 50%, var(--violet) 100%);

  --display: "Funnel Display", "Helvetica Neue", Arial, sans-serif;
  --body: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --gutter: clamp(20px, 4vw, 48px);
  color-scheme: light;
}


/* --- header -------------------------------------------------------------- */

/* The bar stays at the top of the viewport; the header inside it stays the width
 * of the page. Two elements rather than one because the background has to reach
 * both edges of the screen while its contents stay lined up with everything
 * below — so the bar cancels the body gutter with a negative margin and puts it
 * back as padding.
 *
 * A negative margin rather than `width: 100vw`, which counts the scrollbar on
 * platforms that reserve room for one and buys a horizontal scroll with it. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  margin-inline: calc(-1 * var(--gutter));
  padding-inline: var(--gutter);
  /* Translucent so the page reads as moving underneath it, opaque enough that
     124px of headline passing behind the nav is still legible. */
  background: rgb(255 255 255 / 86%);
  backdrop-filter: blur(12px);
  /* Always on, rather than appearing once the page scrolls: fading it in needs a
     scroll listener or an IntersectionObserver sentinel, and that is a lot of
     machinery for one hairline. At the top of the page it reads as the divider
     between the bar and the hero, which is what it is. */
  border-bottom: 1px solid var(--line);
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: 22px;
  max-width: var(--max);
  margin-inline: auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  font-family: var(--display);
  font-weight: 600;
  font-size: 25px;
  letter-spacing: -0.015em;
  color: var(--accent);
}

.brand img { display: block; width: 38px; height: 38px; flex: none; }

/* The wordmark carries the mark's gradient, so the name and the pin beside it
   are the same object in two forms. `color` on .brand is the fallback and has
   to stay a real colour: background-clip painting text means transparent glyphs,
   and where the clip does not apply that is an invisible header. */
.wordmark { display: inline-block; }

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .wordmark {
    background-image: var(--dusk);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

@media (max-width: 560px) {
  .brand { font-size: 20px; gap: 10px; }
}

nav { display: flex; gap: 28px; font-size: 14px; }
nav a { text-decoration: none; color: var(--ink-2); }
nav a:hover { color: var(--ink); }


/* --- footer ---------------------------------------------------------------- */

footer {
  border-top: 1px solid var(--line);
  padding-block: 24px 32px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* Two groups, and on a narrow phone they stack rather than squeeze: the
     copyright takes the first line and the address with its icons the second,
     each flush left, which is what `space-between` does to one item on a row. */
  flex-wrap: wrap;
  gap: 12px;
  font-size: 13px;
  color: var(--muted);
  max-width: var(--max);
  margin-inline: auto;
}

footer a { text-decoration: none; }
footer a:hover { color: var(--ink); }


/* --- social ---------------------------------------------------------------
 * Seven marks, drawn rather than fetched, for the same reason as the globe
 * below: the CSP is `default-src 'self'` and a row of icons is not worth seven
 * requests or a font. Every path is a single `currentColor` fill, so the row
 * inherits the footer's grey and lifts to the accent on hover.
 *
 * Two of the seven have no account yet. They are drawn anyway, greyed and
 * inert, so the row reads as a set with two not yet open rather than as five
 * arbitrary ones — and so turning one on later is an href, not a redraw. */

.footer-id { flex: none; }

/* **The copyright and the privacy link are one group.** The footer is
   `space-between` with `flex-wrap`, so two bare items become two items that
   drift apart at every width and then wrap in an order nobody chose. Grouped,
   the pair holds together and the footer still has exactly two things in it —
   which is what the wrap rule above was written for. */
.footer-legal {
  display: flex;
  align-items: center;
  /* Wider than the icon row's 10px: these are two words with nothing between
     them but space, and the space is the only separator they get. */
  gap: 16px;
  flex-wrap: wrap;
}

/* **The icons belong to the address, not to the copyright.** One row with it
   and immediately before it, so the pair reads as one way to reach us rather
   than as decoration at the far end of the line. */
.footer-contact {
  display: flex;
  align-items: center;
  gap: 10px;
  /* Only ever used below roughly 320px, where the seven icons and the address
     no longer share a line. They stay a group when they wrap, which is the
     whole reason they are in a wrapper of their own. */
  flex-wrap: wrap;
}

.social {
  display: flex;
  align-items: center;
  /* One pixel, not two. The row plus the address comes to 276px at this gap,
     which is what a 320px phone leaves once the gutter is taken — the
     difference between the two sharing a line there and not. */
  gap: 1px;
  list-style: none;
  /* Pulled back by the hit-area padding at each end, so what the eye measures
     between the row and the address is the 10px the group asks for rather
     than 10 plus two invisible edges. */
  margin: 0 -6px;
  padding: 0;
}

.social a {
  display: flex;
  padding: 6px;
  border-radius: 6px;
  color: var(--muted);
  transition: color 0.2s, background 0.2s;
}

.social a:hover { color: var(--accent); background: var(--accent-soft); }

/* **One em, so the icons are the size of the address beside them** — at every
   width, rather than at the one the number was picked on. `footer` sets 13px
   today; change that and the row follows without anybody remembering to. */
.social svg {
  width: 1em;
  height: 1em;
  display: block;
  fill: currentColor;
}

/* Not a link and not focusable: there is nowhere to go yet. Lighter than
   --muted so it reads as off rather than as merely another grey. */
.social .off {
  display: flex;
  padding: 6px;
  color: var(--muted);
  opacity: 0.4;
}



/* --- the menu, on a narrow screen -----------------------------------------
 * Below 640px the bar cannot hold a wordmark, three links and a language
 * picker — measured, not guessed: those come to roughly 490px before gutters.
 * So they collapse into one control.
 *
 * **No script, and no duplicated markup.** The `<details>` is a toggle and
 * nothing else; the nav and the picker stay exactly where they are in the
 * document and are revealed by `[open] ~`. Duplicating the links into a second
 * hidden menu would be the other way to do this, and it means every link in the
 * bar exists twice in the page for a crawler to reconcile.
 *
 * The panel pushes the page down rather than floating over it. The bar is
 * `position: sticky` with a blur behind it, and an absolutely positioned panel
 * inside a stacking context like that is how a menu ends up clipped on exactly
 * one browser.
 *
 * The picker is inside the panel, not beside the toggle: a language control
 * sitting next to a hamburger is two menus competing for the same corner. */

.menu { display: none; }

@media (max-width: 640px) {
  header { flex-wrap: wrap; row-gap: 0; }

  .menu {
    display: block;
    /* Pushes the toggle to the right edge; the brand keeps the left. */
    margin-inline-start: auto;
  }

  .menu > summary {
    list-style: none;
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border-radius: 10px;
    color: var(--ink-2);
    transition: background 0.2s, color 0.2s;
  }

  .menu > summary::-webkit-details-marker { display: none; }
  .menu > summary:hover { background: var(--wash); color: var(--ink); }
  .menu > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

  /* Three bars from one element: the middle is the box, the outer two are its
     pseudo-elements. They fold into a cross when the menu is open, so the
     control says whether it is a way in or a way out. */
  .bars, .bars::before, .bars::after {
    display: block;
    width: 20px;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
  }

  .bars { position: relative; transition: background 0.2s; }
  .bars::before, .bars::after { content: ""; position: absolute; left: 0; }
  .bars::before { top: -6px; }
  .bars::after { top: 6px; }
  .bars::before, .bars::after { transition: transform 0.2s; }

  .menu[open] .bars { background: transparent; }
  .menu[open] .bars::before { transform: translateY(6px) rotate(45deg); }
  .menu[open] .bars::after { transform: translateY(-6px) rotate(-45deg); }

  header > nav,
  header > .lang { display: none; }

  .menu[open] ~ nav,
  .menu[open] ~ .lang {
    display: flex;
    width: 100%;
  }

  .menu[open] ~ nav {
    flex-direction: column;
    gap: 2px;
    padding-block: 8px 4px;
    border-top: 1px solid var(--line);
    margin-top: 8px;
  }

  .menu[open] ~ nav a { padding-block: 10px; font-size: 15px; }

  .menu[open] ~ .lang { padding-bottom: 12px; }

  /* The 560px rule further down collapses this summary to a bare globe with
     `font-size: 0`, which was right while it shared the bar with a wordmark and
     three links. Inside the panel it has a whole row, and a globe with no
     language written beside it does not tell you which language you are
     currently reading — which is the one question the control answers. */
  .menu[open] ~ .lang summary { font-size: 14px; gap: 7px; padding: 8px 10px; }

  @media (prefers-reduced-motion: reduce) {
    .bars, .bars::before, .bars::after { transition: none; }
  }
}



/* --- language picker ------------------------------------------------------
 * A <details> and nine links, and no script: the CSP is `script-src 'self'`
 * and a dropdown does not need to be a fourth JavaScript file. <details> opens
 * on click and on Enter, closes on Escape, and is announced as a disclosure,
 * which is what it is. tools/build-i18n.py writes the markup. */

.lang { position: relative; flex: none; }

.lang summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  color: var(--ink-2);
  padding: 6px 10px;
  border-radius: 999px;
  white-space: nowrap;
  transition: color 0.2s, background 0.2s;
}

.lang summary::-webkit-details-marker { display: none; }
.lang summary:hover { color: var(--ink); background: var(--wash); }
.lang summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lang[open] summary { color: var(--ink); background: var(--wash); }

/* A globe, drawn rather than fetched: one more request for 14px of icon is a
   request too many, and an emoji globe renders differently on every platform. */
.lang .globe {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1.2px solid currentColor;
  position: relative;
  flex: none;
}

.lang .globe::before,
.lang .globe::after {
  content: "";
  position: absolute;
  inset: -1.2px;
  border: 1.2px solid currentColor;
  border-radius: 50%;
}

.lang .globe::before { border-width: 0 0 0 1.2px; left: 50%; margin-left: -1.2px; }
.lang .globe::after  { border-width: 1.2px 0 0; top: 50%; margin-top: -1.2px; border-radius: 0; }

.lang ul {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 20;
  margin: 0;
  padding: 6px;
  list-style: none;
  min-width: 168px;
  background: #fff;
  border-radius: 10px;
  box-shadow: inset 0 0 0 1px var(--line), 0 12px 32px rgb(22 16 31 / 10%);
}

.lang ul a {
  display: block;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 14px;
  color: var(--ink-2);
  text-decoration: none;
}

.lang ul a:hover { background: var(--wash); color: var(--ink); }
.lang ul a[aria-current="true"] { color: var(--ink); font-weight: 500; }

/* Below the nav's own breakpoint the bar is tight, so the picker keeps the
   globe and drops the language name rather than wrapping the header. */
@media (max-width: 560px) {
  .lang summary { font-size: 0; gap: 0; padding: 6px; }
  .lang summary .globe { font-size: 14px; }
}
