/*
 * The chrome: the top bar, the nav, the account menu, the page column.
 *
 * Extracted from desktop/templates/base.html, where it was 276 lines of inline
 * <style> on every page. It moved out for a reason beyond tidiness: the SaaS in
 * saas/ has to look like the SAME PRODUCT, and it was approximating this by
 * hand — a different header, a different page width, cards that were nearly but
 * not quite these ones. Two designs drifting apart is how one product starts
 * looking like two.
 *
 * Sits on top of design-system.css, which holds the tokens. This holds the
 * layout those tokens are spent on.
 *
 * Copied into saas/static/ by macapp/build.sh and by hand until the two are
 * ever packaged together — a copy that drifts is the cost, and it is smaller
 * than the cost of two headers.
 */

  /*
   * Shell styles. Everything visual comes from design-system.css — this file
   * only lays things out.
   *
   * Light only, and explicitly so: the Teacher's Cart canvas defines one
   * palette. Deriving a dark ramp from it would mean inventing eight or nine
   * colours the design system never specified, which is how a system quietly
   * stops matching itself. color-scheme is pinned so form controls and
   * scrollbars follow suit instead of going dark underneath a light page.
   */
  :root { color-scheme: light; }

  * { box-sizing: border-box; }
  body {
    margin: 0;
    font-family: var(--tc-font);
    background: var(--tc-surface);
    color: var(--tc-ink);
    -webkit-font-smoothing: antialiased;
  }
  a { color: var(--tc-coral); text-decoration: none; }
  a:hover { text-decoration: underline; }

  /* ── top bar ───────────────────────────────────────────────────────── */
  /* The bar spans, its contents do not. On a wide screen the brand sat against
     the left bezel and Sign out against the right, while everything below them
     stopped short — so the header belonged to a different page than the page.
     The white and the rule still run edge to edge; only the row inside is held
     to the same column as the content.

     Which means this number and .wrap.wide are ONE measurement written twice:
     when the pages went to 1,440 and this stayed at 1,240, the brand stopped
     lining up with the heading under it. Same token, so they cannot drift
     again. */

  .skiplink {
    position: absolute; left: -9999px; top: 0; z-index: 100;
    background: var(--tc-ink); color: var(--tc-white);
    padding: 12px var(--tc-s4); border-radius: 0 0 var(--tc-r-control) 0;
    font: 700 14px/1 var(--tc-font); text-decoration: none;
  }
  .skiplink:focus { left: 0; }

  .topbar {
    background: var(--tc-white);
    border-bottom: 1px solid var(--tc-border);
    position: sticky; top: 0; z-index: 40;
  }
  .topbar-inner {
    display: flex; align-items: center; gap: var(--tc-s4);
    max-width: var(--tc-page); margin: 0 auto;
    padding: 0 var(--tc-s6); height: 64px;
  }
  /* ── The account menu ─────────────────────────────────────────────── */
  .acct { position: relative; flex: none; }
  .acctbtn {
    border: none; background: none; padding: 0; cursor: pointer;
    display: grid; place-items: center; border-radius: var(--tc-r-control);
  }
  .avatar {
    width: 34px; height: 34px; border-radius: var(--tc-r-control);
    display: grid; place-items: center; flex: none;
    background: var(--tc-coral); color: var(--tc-white);
    font: 700 14px/1 var(--tc-font); letter-spacing: 0;
  }
  .avatar.big { width: 42px; height: 42px; font-size: 17px; }
  .acctbtn:hover .avatar { filter: brightness(.94); }
  .acctbtn:focus-visible { outline: 2px solid var(--tc-indigo); outline-offset: 2px; }

  .acctmenu {
    position: absolute; right: 0; top: calc(100% + 10px); z-index: 50;
    width: 288px; padding: var(--tc-s2);
    background: var(--tc-white); border: 1px solid var(--tc-border);
    border-radius: var(--tc-r-2xl); box-shadow: var(--tc-shadow-card);
  }
  .acctwho {
    display: flex; align-items: center; gap: var(--tc-s3);
    padding: var(--tc-s3); margin-bottom: var(--tc-s2);
  }
  .acctmail { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .acctitem {
    display: flex; align-items: center; gap: var(--tc-s3);
    padding: var(--tc-s2) var(--tc-s3); border-radius: var(--tc-r-lg);
    text-decoration: none; color: inherit;
  }
  .acctitem:hover { background: var(--tc-surface); text-decoration: none; }
  .acctlines { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .acctico {
    width: 34px; height: 34px; border-radius: var(--tc-r-control); flex: none;
    display: grid; place-items: center;
    background: var(--tc-indigo-tint); color: var(--tc-indigo);
  }
  /* Log out is the one thing here you cannot undo by pressing it again. */
  .acctico.danger { background: var(--tc-coral-tint); color: var(--tc-coral-ink); }
  .acctgo { margin-left: auto; color: var(--tc-disabled); font-size: 18px; line-height: 1; }
  .acctsep { height: 1px; background: var(--tc-border); margin: var(--tc-s2) var(--tc-s3); }

  /* Beside the workers chip, and only when there is nothing running. */
  .wrestart {
    margin-left: var(--tc-s2); height: 30px; padding: 0 12px;
    font: 700 14px/1 var(--tc-font); white-space: nowrap;
    background: var(--tc-coral-tint); color: var(--tc-coral-ink); border: none;
  }
  .wrestart:hover:not(:disabled) { background: var(--tc-coral); color: #fff; }
  .wrestart:disabled { opacity: .6; cursor: default; }

  .brand {
    font: 700 20px/1 var(--tc-font); letter-spacing: -.03em;
    color: var(--tc-ink); text-decoration: none;
    /* The tap target, not the type: 17px of text in a
     56px bar is a small thing to hit on a phone. */
  padding-block: 6px;
  /* Never gives way. The bar shrinks its items together when it runs out of
     room, and a brand without these broke into "WP" over "Render" on every
     SaaS page at 1280px — the nav is the part meant to give, not the name. */
  flex: none; white-space: nowrap;
}
  .brand:hover { text-decoration: none; }
  .brand span { color: var(--tc-coral); }

  /* Which app you are in, said in the one place that is on every screen.
     The two apps are the same code on two ports and were identical in the
     header, so the only way to tell them apart was to read the nav and know
     which items belong to which. */
  .appmark {
    font: 700 14px/1 var(--tc-font); letter-spacing: .06em;
    text-transform: uppercase; white-space: nowrap;
    background: var(--tc-amber-tint); color: var(--tc-amber-ink);
    padding: 6px 9px; border-radius: var(--tc-r-control);
    margin-left: var(--tc-s3); flex: none;
  }
  .grow { flex: 1; }

  /* Shrinkable and scrollable. A third nav item pushed Sign out 63px past the
     right edge of a 390px screen — the bar has a fixed brand and a fixed button
     at either end, so the nav is the only part that can give. */
  .topnav {
    display: flex; gap: var(--tc-s1); margin-left: var(--tc-s4);
    min-width: 0; overflow-x: auto; scrollbar-width: none;
  }
  .topnav::-webkit-scrollbar { display: none; }
  .topnav a { flex: none; }
  .topnav a {
    font: 500 14px/1 var(--tc-font); color: var(--tc-body);
    padding: 9px var(--tc-s3); border-radius: var(--tc-r-control);
    text-decoration: none;
  }
  .topnav a:hover { background: var(--tc-surface); color: var(--tc-ink); text-decoration: none; }
  .topnav a.on { background: var(--tc-coral-tint); color: var(--tc-coral-ink); }

  /* The worker chip. Serper's credits used to sit beside it and no longer do:
     one number about a shared pool, on every screen, next to a worker count it
     has nothing to do with. They are on the Dashboard's System panel and on
     Settings, where there is room to say what they mean. The Claude windows
     were never here for the older version of the same reason — one figure
     cannot describe four accounts. */
  .usage {
    display: flex; align-items: center; gap: var(--tc-s3);
    padding: 6px var(--tc-s3); border-radius: var(--tc-r-control);
    background: var(--tc-surface); text-decoration: none;
  }
  .usage:hover { background: var(--tc-border); text-decoration: none; }
  .uwin { display: flex; align-items: center; gap: 6px; }
  .ulabel {
    font: 500 14px/1 var(--tc-font); letter-spacing: .06em; text-transform: uppercase;
    color: var(--tc-meta);
  }
  .ubar {
    display: block; width: 42px; height: 5px; border-radius: var(--tc-r-control);
    background: var(--tc-border); overflow: hidden;
  }
  .ubar i { display: block; height: 100%; background: var(--tc-green-ink); transition: width .3s; }
  /* Amber past two-thirds, coral past 90% — a build is an hour of work, so
     knowing before you start matters more than knowing when it stops. */
  .ubar.warn i { background: var(--tc-amber-ink); }
  .ubar.hot  i { background: var(--tc-coral); }
  .upct { font: 500 14px/1 var(--tc-font); color: var(--tc-body); min-width: 26px; }
  /* A device name is a name, not a measurement: it needs no minimum column and
     it must not be clipped. "jaydeep's MacBook Pro" was cut to "jaydeep's
     MacBo…", losing the only part that tells two Macs apart. */
  .upct.uname { min-width: 0; white-space: nowrap; }
  /* When it last reported. Quieter than the name — it is the answer to a
     second question, and the name is the one being scanned for. */
  .usync { font: 400 14px/1 var(--tc-font); color: var(--tc-meta); white-space: nowrap; }
  /* Tick or cross, in front of the name. Sized to the text beside it so the
     chip keeps one optical line. */
  .udot { flex: none; display: block; }
  .udot.ok  { color: var(--tc-green-ink); }
  .udot.bad { color: var(--tc-coral); }
  /* Whose limits these are. Two unlabelled meters side by side said nothing
     about which service was near its ceiling. */
  .ulabel.owner { color: var(--tc-ink); font-size: 14px; }
  .usage.busy { opacity: .5; }

  /* What is building, in the header. */
  .buildwrap { position: relative; }
  .buildbtn { position: relative; color: var(--tc-meta); }
  .buildbtn:hover { color: var(--tc-ink); }
  /* Turning while something is. The header says "working" before it is read,
     which is the whole reason the control is in the header. */
  .buildbtn.live svg { animation: buildspin 2.4s linear infinite; color: var(--tc-coral); }
  @keyframes buildspin { to { transform: rotate(360deg); } }
  @media (prefers-reduced-motion: reduce) {
    .buildbtn.live svg { animation: none; }
  }
  /* 14px, like everything else. It was 12 in a 16px bubble, which is the
     size a count badge is everywhere — but the floor is the floor, and the
     badge grew to fit the number rather than the number shrinking to fit the
     badge. The pills that keep 12px keep it because they hold a WORD. */
  .buildn {
    position: absolute; top: -5px; right: -5px; min-width: 20px; height: 20px;
    padding: 0 5px; border-radius: 999px; background: var(--tc-coral);
    color: #fff; font: 500 14px/20px var(--tc-font); text-align: center;
  }
  .buildpop {
    position: absolute; right: 0; top: calc(100% + 8px); z-index: 60;
    width: 300px; max-height: 60vh; overflow-y: auto;
    background: var(--tc-white); border: 1px solid var(--tc-border);
    border-radius: var(--tc-r-xl); box-shadow: var(--tc-shadow-over);
    padding: var(--tc-s4);
  }
  .buildrow {
    display: block; padding: var(--tc-s2) 0; color: inherit;
    text-decoration: none;
  }
  .buildrow + .buildrow { border-top: 1px solid var(--tc-border); }
  .buildrow:hover { text-decoration: none; }
  .buildrow .nm { font: 500 14px/1.3 var(--tc-font); color: var(--tc-ink); }
  .buildrow .sub { font: 400 14px/1.4 var(--tc-font); color: var(--tc-meta); }
  /* The "synced 2 min ago" half of the Mac chip goes first: the name and the
     tick say whether the Mac is there, which is what a glance wants. */
  @media (max-width: 1280px) { .usage .usync { display: none; } }
  @media (max-width: 1040px) { .usage { display: none; } }

  .wrap { max-width: 940px; margin: 0 auto; padding: var(--tc-s7) var(--tc-s5) 96px; }
  /* 940px is right for reading — a settings form, a thread. It is not right for
     a table of five columns whose last one is five icon buttons: that came to
     about 1,130px and the page scrolled sideways. A page that holds one asks
     for the room instead of every page paying for it. */
  /* The design states it as a rule rather than a number: "Window 1440x900
     minimum, content padding 32px on every screen". So a wide page fills what
     it is given up to a sensible reading width, rather than stopping at 1240
     and leaving a band of nothing down both sides of a 1600px display. */
  .wrap.wide { max-width: var(--tc-page); padding-inline: var(--tc-s6); }

  /* ── flash ─────────────────────────────────────────────────────────── */
  .flash {
    padding: var(--tc-s3) var(--tc-s4);
    border-radius: var(--tc-r-lg);
    margin-bottom: var(--tc-s4);
    font: 500 14px/1.4 var(--tc-font);
  }
  .flash.error { background: var(--tc-coral-tint); color: var(--tc-coral-ink); }
  .flash.ok    { background: var(--tc-green-tint); color: var(--tc-green-ink); }

  /* ── the signed-out column ─────────────────────────────────────────────
     Sign in, sign up, forgot, reset: the same 400px column with a different
     form in it. It was declared inline in both apps' templates, which is two
     copies of one measurement.

     THE FLASH BELONGS TO THE COLUMN. base.html renders it inside .wrap, which
     is 940px, so "Wrong email or password" arrived as a band more than twice
     the width of the card it was about, its text starting somewhere off to
     the left of the form, separated from it by the column's own 6vh. It is
     the width of the card now, centred, directly above it. */
  .auth { max-width: 400px; margin: 0 auto; }
  .auth .tc-card { padding: var(--tc-s7); }
  .wrap.auth-page { padding-top: 6vh; }
  .wrap.auth-page .flash {
    max-width: 400px; margin-inline: auto; text-align: center;
  }

  /* ── toasts and dialogs ────────────────────────────────────────────────
     A native alert() steals focus, blocks the page, cannot be styled and has
     to be dismissed before anything else happens — for messages that are
     usually just "that worked". These say the same thing without interrupting,
     and look like the rest of the app. */
  .toasts {
    position: fixed; top: 76px; right: var(--tc-s5); z-index: 70;
    display: flex; flex-direction: column; gap: var(--tc-s2);
    max-width: min(420px, calc(100vw - 32px)); pointer-events: none;
  }
  .toast {
    pointer-events: auto;
    padding: var(--tc-s3) var(--tc-s4); border-radius: var(--tc-r-lg);
    background: var(--tc-white); color: var(--tc-ink);
    border: 1px solid var(--tc-border); box-shadow: var(--tc-shadow-card);
    font: 400 14px/1.45 var(--tc-font);
    display: flex; gap: var(--tc-s3); align-items: flex-start;
    animation: toast-in .16s ease-out;
  }
  .toast.ok    { border-color: var(--tc-green-ink); }
  .toast.error { border-color: var(--tc-coral); }
  .toast .dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex: none; }
  .toast.ok .dot    { background: var(--tc-green-ink); }
  .toast.error .dot { background: var(--tc-coral); }
  .toast .x {
    border: 0; background: none; cursor: pointer; color: var(--tc-meta);
    font: 500 15px/1 var(--tc-font); padding: 0 0 0 var(--tc-s2);
  }
  @keyframes toast-in { from { opacity: 0; transform: translateY(-6px) } }
  @media (prefers-reduced-motion: reduce) { .toast { animation: none } }

  .ask {
    position: fixed; inset: 0; z-index: 80; display: none;
    background: rgba(20,18,17,.45); align-items: center; justify-content: center;
    padding: var(--tc-s5);
  }
  .ask.open { display: flex; }
  .ask-card {
    background: var(--tc-white); border-radius: var(--tc-r-3xl);
    padding: var(--tc-s6); max-width: 440px; width: 100%;
    box-shadow: var(--tc-shadow-card);
  }

  /* ── state badges ──────────────────────────────────────────────────── */
  /* THE ONE EXCEPTION TO THE 14px FLOOR, asked for and worth stating.
     A badge is not read, it is recognised: READY, NEW, BUILDING, FAILED are
     five uppercase words in a tinted pill, and the pill is doing most of the
     work. At 14px the pill grew to a size that competed with the name beside
     it for a word nobody has to parse.
     See test_nothing_in_either_app_is_smaller_than_fourteen_pixels, which
     names this rule rather than being softened for it. */
  .state {
    display: inline-flex; align-items: center; gap: var(--tc-s1);
    font: 500 12px/1.2 var(--tc-font);
    text-transform: uppercase; letter-spacing: .06em;
    padding: 6px var(--tc-s3); border-radius: var(--tc-r-control);
    background: var(--tc-surface); color: var(--tc-meta);
    white-space: nowrap;
  }
  .state.new      { background: var(--tc-surface);     color: var(--tc-meta); }
  /* PREPARING had no rule, so it fell through to the base — surface on
     surface, which on this page's own surface is an invisible pill. It read
     as grey text beside the name and not as a badge at all.
     Indigo, with the in-flight dot below: it is the app standing the site up,
     which is work happening now. It shares the colour with `building` because
     both mean exactly that, they never appear at once, and the word says
     which — a sixth tint for a state that lasts a minute would be a colour
     nobody learns. */
  .state.preparing { background: var(--tc-indigo-tint); color: var(--tc-indigo); }
  .state.queued   { background: var(--tc-amber-tint);  color: var(--tc-amber-ink); }
  .state.building { background: var(--tc-indigo-tint); color: var(--tc-indigo); }
  /* BLUE, not green. Green now means one thing on this screen and one only:
     the site is UP. Ready says the build finished, which is a different fact
     about a different moment — a site can be ready and down, or building and
     up, and the two colours are what let you see which at a glance. */
  .state.ready    { background: var(--tc-blue-tint);   color: var(--tc-blue); }
  .state.failed   { background: var(--tc-coral-tint);  color: var(--tc-coral); }

  /* RUNNING IS NOT A SIXTH VALUE OF THIS PILL. `state` is how the BUILD went
     — new, queued, building, ready, failed — and it changes when a build
     changes it. Whether the containers are up changes on its own, without a
     build happening at all.

     So it is a SECOND pill, beside the first, shown only while the site is
     up. One pill would mean a running site could not also say its build
     failed, which is exactly the site somebody is looking for. */
  .state.running  { background: var(--tc-green-tint);  color: var(--tc-green-ink); }
  .state.running::before {
    content: ""; width: 6px; height: 6px; border-radius: 50%;
    background: currentColor; flex: none;
  }

  /* A build in flight should read as in flight without needing the log. */
  .state.preparing::before,
  .state.building::before,
  .state.queued::before {
    content: ""; width: 6px; height: 6px; border-radius: 50%;
    background: currentColor; animation: tc-pulse 1.4s ease-in-out infinite;
  }
  @keyframes tc-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .25 } }
  @media (prefers-reduced-motion: reduce) {
    .state.preparing::before, .state.building::before,
    .state.queued::before { animation: none; }
  }

  .muted { color: var(--tc-meta); }
  .mono  { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px; }

  @media (max-width: 640px) {
    .wrap   { padding: var(--tc-s5) var(--tc-s4) 80px; }
    .topbar-inner { padding: 0 var(--tc-s4); height: 58px; gap: var(--tc-s2); }
    .brand  { font-size: 17px; flex: none; }
    .topnav { margin-left: var(--tc-s2); }
    .topnav a { padding: 8px var(--tc-s2); font-size: 14px; }
    /* A scroller with a hidden scrollbar cut "AI" in half and gave no sign
       there was more. The fade says the row continues; ui.js scrolls the
       current page's link into view. */
    .topnav { -webkit-mask-image: linear-gradient(to right, #000 82%, transparent);
              mask-image: linear-gradient(to right, #000 82%, transparent); }
  }
