/* chrome.css — the one header shared by every page of the site: the bar with the site name and the
   explorer's views, and the frame geometry that both the write-up (.frame) and the bar (.chrome)
   align to. Loaded after the site's one token vocabulary everywhere. */

:root {
  --col: 820px;        /* the essay's text column */
  --rail: 220px;       /* the essay's contents rail */
  --frame-gap: 40px;
  --frame-pad: 32px;
  --bar-pad: 5px;      /* the bar's own top and bottom padding; the open menu measures off it */
  --bar-h: calc(40px + 2 * var(--bar-pad));   /* one bar row: a 40px item and its padding */
  --menu-ground: #fff3dc;   /* the open menu's ground */
  --menu-anim: .24s;        /* the hamburger's cross, its amber and its rows, all on one clock */
  --menu-ease: cubic-bezier(.4, 0, .2, 1);
}
@media (prefers-reduced-motion: reduce) { :root { --menu-anim: 0s; } }
@media (max-width: 1400px) { :root { --rail: 170px; } }
@media (max-width: 900px)  { :root { --frame-pad: 18px; } }

/* frame: rail | column, centred. The bar is laid out on the same grid so its rule and its title
   land exactly where the essay's column does, on every page and at every width. */
.frame, .chrome {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, var(--col));
  column-gap: var(--frame-gap);
  max-width: calc(var(--rail) + var(--frame-gap) + var(--col) + 2 * var(--frame-pad));
  margin: 0 auto;
  padding: 0 var(--frame-pad);
  box-sizing: border-box;
}

/* the bar, at the top of the page */
.chrome {
  position: sticky; top: 0; z-index: 50;
  background: var(--vivid-background);
}
.chrome-inner {
  grid-column: 2;
  display: flex; align-items: center; gap: 17px;
  margin: 0 calc(-1 * var(--frame-pad));
  padding: var(--bar-pad) var(--frame-pad);
  border-bottom: 1px solid var(--hair);
}
.story-link {
  display: inline-flex; align-items: center; min-height: 40px;
  margin-right: 9px; padding: 0 2px;
  border-bottom: 2px solid transparent;
  color: var(--ink); font-family: var(--serif); font-size: 17px;
  text-decoration: none; white-space: nowrap;
}
/* Hover is a hairline under a label and the ink rule is the current view's alone, so a hovered
   label never reads as the one you are on. */
.story-link:hover, .story-link:focus-visible { border-bottom-color: var(--rule); }
.story-link[aria-current="page"] { border-bottom-color: var(--ink); }
.chrome .nav { display: flex; gap: 2px; }
/* Stated at the bottom rung of the ladder below -- 4px of padding, 11px labels -- so every step up
   is a min-width that adds something back and no width falls between two rules. */
.chrome .nav a, .chrome .nav button, .chrome .nav-more > summary {
  appearance: none; display: flex; align-items: center; min-height: 40px;
  padding: 0 4px; border: 0; border-bottom: 2px solid transparent; background: transparent;
  color: var(--dull-foreground); font-family: var(--sans); font-size: 11px;
  text-decoration: none; white-space: nowrap; cursor: pointer;
}
.chrome .nav a:not([aria-current="page"]):hover,
.chrome .nav a:not([aria-current="page"]):focus-visible { color: var(--ink); border-bottom-color: var(--rule); }
.chrome .nav [aria-current="page"], .chrome .nav [aria-selected="true"] { color: var(--ink); border-bottom-color: var(--ink); }
/* "New" beside a label, until the date in its data-until; the script at the end of the bar takes
   it out of the page then (build_explorer.bar). The Sites index's badge, restated here because
   that one is explorer.css's and the bar is on pages that never load it: outlined slate, which is
   what tokens.css leaves for machinery -- green and amber are spent on where evidence came from,
   and a badge makes no such claim. Its own colour, so the label going to ink under the cursor
   does not take it along. */
.chrome .nav .nav-new {
  display: none;                                  /* the ladder's top two rungs put it back */
  margin-left: 7px; padding: 0 4px;
  border: 1px solid var(--ui); color: var(--ui);
  font-size: 9px; font-weight: 600; line-height: 15px; letter-spacing: .06em; text-transform: uppercase;
}

/* ----------------------------------------------------------------- the row's four rungs

   Seven entries do not fit a narrowing window all at once, and there is more to give up than the
   row itself before the hamburger has to take it: first the air around each label, then the size
   of the labels, then the New badge, which is temporary anyway.  So the row gives them up in that
   order, one at a time, and only when the last of them is spent does the menu fold up.

   Measured in Chrome on 2026-09-11 -- the seven labels, the story link, the gaps and the badge:

      rung                      row     step     slack at the step
      8px / 13px / badge      783px    900px     37px   (the column's, not the window's -- below)
      4px / 13px / badge      727px    840px     77px
      4px / 11px / badge      656px    760px     68px
      4px / 11px / no badge   616px    720px     68px   <- stated above, as the base
      hamburger                 --     under 720px

   Each step is its rung's width plus this width's --frame-pad plus a tenth, the headroom for a
   system font wider than this Mac's.

   The top rung is the exception, and the reason is worth knowing before touching this row:
   .chrome-inner is laid out on the essay's grid, so the row gets --col (820px) and not a pixel
   more, at every window from 856px up.  Widening the window past that buys nothing, which is why
   the top rung's slack is 37px rather than a tenth of 783px, and why the 14px padding this row
   had above 800px before the seventh entry is gone: at 14px these seven measure 867px and would
   overhang the column at any window size.  Measure an eighth entry against the column, not against
   the window -- there are 37px going spare up there, and 77px once the badge expires. */
.chrome .nav-more { display: none; }

@media (min-width: 760px) { .chrome .nav .nav-new { display: inline-block; } }
@media (min-width: 840px) { .chrome .nav a, .chrome .nav button { font-size: 13px; } }
@media (min-width: 900px) { .chrome .nav a, .chrome .nav button { padding: 0 8px; } }

/* The bottom of the ladder: nothing left to give up, so the hamburger appears, and opening it
   floods the screen under the bar with amber, the seven labels fading in on top of it while the
   three bars turn into the cross that shuts it again. `not all and` rather than a max-width, so
   that no fractional viewport width falls between this and the bottom rung above.
   All of it keys off the <details>'s own open state, so it needs no script on either half, and
   every transition is on --menu-anim, which prefers-reduced-motion sets to zero. */
@media not all and (min-width: 720px) {
  .chrome {
    --menu-row: 46px;                                         /* one row of the open menu */
    --menu-top: calc(var(--bar-h) + 10px);   /* its first row, just under the bar */
  }
  /* a viewport too short for seven 46px rows under the bar: a phone held on its side, a small window */
  @media (max-height: 420px) { .chrome { --menu-row: 34px; } }

  .chrome-inner { position: relative; flex-wrap: nowrap; gap: 10px; }
  /* raised, so the story link stays legible on the amber while the menu is over everything else */
  .story-link { position: relative; z-index: 1; margin-right: 0; font-size: 16px; }
  .chrome .nav { flex: 1 1 auto; justify-content: flex-end; gap: 0; }

  /* The button. Its two pseudo-elements are the outer bars, which rotate into the cross; the
     middle bar is the button's own background image, which shrinks from its centre to nothing --
     three boxes are needed and an element has only two pseudo-elements to give. */
  .chrome .nav-more { position: static; display: block; }
  .chrome .nav-more > summary {
    position: relative; width: 40px; justify-content: center; padding: 0; font-size: 0; list-style: none;
    background-image: linear-gradient(currentColor, currentColor);
    background-repeat: no-repeat; background-position: center; background-size: 17px 1.5px;
    transition: background-size var(--menu-anim) var(--menu-ease);
  }
  .chrome .nav-more > summary::-webkit-details-marker { display: none; }
  .chrome .nav-more > summary::before,
  .chrome .nav-more > summary::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 17px; height: 1.5px; margin: -.75px 0 0 -8.5px; background: currentColor;
    transition: transform var(--menu-anim) var(--menu-ease);
  }
  .chrome .nav-more > summary::before { transform: translateY(-5px); }
  .chrome .nav-more > summary::after { transform: translateY(5px); }
  /* the cross says the menu is open on its own; the bar's rule under an open menu would only read
     as a stray mark next to it */
  .chrome .nav-more[open] > summary { color: var(--ink); background-size: 0 1.5px; border-bottom-color: transparent; }
  .chrome .nav-more[open] > summary::before { transform: rotate(45deg); }
  .chrome .nav-more[open] > summary::after { transform: rotate(-45deg); }

  /* The amber. One fixed box that is there in both states and only changes opacity, so it fades in
     and out evenly and nothing in the bar is laid out again to do it. Untouchable while the menu
     is shut, so the page under it can be read and clicked as usual; once open it is also what
     keeps the page behind from being clicked, and a tap on it is the outside click that shuts the
     menu on the halves whose script says so. */
  .chrome .nav::before {
    content: ""; position: fixed; top: 0; left: 0; right: 0; bottom: 0;
    background: var(--menu-ground); opacity: 0; pointer-events: none;
    transition: opacity var(--menu-anim) var(--menu-ease);
  }
  .chrome .nav:has(.nav-more[open])::before { opacity: 1; pointer-events: auto; }

  /* The rows. Every one of them is fixed to the viewport at its own place in the stack, in both
     states, and opening the menu changes nothing but whether they are shown -- if their layout
     depended on the open state instead, the moment the menu shut they would fall back into the
     bar and lay themselves out across it, wrapped, for as long as the fade-out lasted.
     Being fixed, they need their own row number: the seven labels are the first seven children of
     .nav, and the <details> after them is the button, which nothing positions.  An eighth label
     needs another line here.  They are full width, so the bar's rule under the current view would
     read as a divider across the menu; it is marked in the gutter instead, 10px left of labels
     that line up with the story link above them. */
  .chrome .nav > :nth-child(1) { --i: 0; }
  .chrome .nav > :nth-child(2) { --i: 1; }
  .chrome .nav > :nth-child(3) { --i: 2; }
  .chrome .nav > :nth-child(4) { --i: 3; }
  .chrome .nav > :nth-child(5) { --i: 4; }
  .chrome .nav > :nth-child(6) { --i: 5; }
  .chrome .nav > :nth-child(7) { --i: 6; }
  /* The badge comes back: the row gave it up for want of width, and a menu row is the full width
     of the screen. */
  .chrome .nav .nav-new { display: inline-block; }
  .chrome .nav > a, .chrome .nav > button {
    position: fixed; top: calc(var(--menu-top) + var(--i) * var(--menu-row));
    left: var(--frame-pad); right: var(--frame-pad);
    height: var(--menu-row); min-height: 0;
    justify-content: flex-start; margin-left: -12px; padding: 0 0 0 10px; font-size: 15px;
    border-bottom-color: transparent; border-left: 2px solid transparent;
    /* Shut: hidden, which keeps them out of the focus order, out of the a11y tree and out of
       hit-testing, exactly as `display: none` would -- but leaves them rendered, which is what
       lets them fade in and back out. `visibility` is the property that holds a fade-out on its
       own: mid-transition it counts as visible and flips only at the end, in every engine.
       (`display` with `transition-behavior: allow-discrete` reads better and does the same in
       Chrome, but Firefox 154 drops the rows at once on the way out -- measured 2026-09-03 --
       and it needs @starting-style to fade them in, which this does not.) */
    visibility: hidden; opacity: 0; transform: translateY(-6px);
    transition: opacity var(--menu-anim) var(--menu-ease),
                transform var(--menu-anim) var(--menu-ease),
                visibility var(--menu-anim) var(--menu-ease);
  }
  /* stated at the specificity of the bar's own rule for the current view, and after it, so that
     the rule that marks it up there does not come back as a divider down here */
  .chrome .nav [aria-current="page"], .chrome .nav [aria-selected="true"] {
    border-bottom-color: transparent; border-left-color: var(--ink);
  }
  /* and hover is marked in the gutter too, in the hairline, so no row grows a divider */
  .chrome .nav a:not([aria-current="page"]):hover,
  .chrome .nav a:not([aria-current="page"]):focus-visible {
    border-bottom-color: transparent; border-left-color: var(--rule);
  }
  /* Open: show the rows. Nothing here moves anything. */
  .chrome .nav:has(.nav-more[open]) > a,
  .chrome .nav:has(.nav-more[open]) > button { visibility: visible; opacity: 1; transform: none; }
}

/* Where an anchor jump or a scrollIntoView lands: 15px clear of what is pinned above the page --
   the bar and its rule -- rather than tucked underneath it. Stated as the sum so that changing the
   bar's row carries the landing spot with it. */
html { scroll-padding-top: calc(var(--bar-h) + 1px + 15px); }

/* a plain content column aligned with the essay's text column: same frame width, and the left
   padding steps past the rail so the text starts where the essay's does */
.framed-column {
  max-width: calc(var(--rail) + var(--frame-gap) + var(--col) + 2 * var(--frame-pad));
  margin: 0 auto;
  padding-left: calc(var(--frame-pad) + var(--rail) + var(--frame-gap));
  padding-right: var(--frame-pad);
  box-sizing: border-box;
}

/* below the rail breakpoint the frame is a single column; stated last so it wins */
@media (max-width: 1320px) {
  .frame, .chrome { grid-template-columns: minmax(0, var(--col)); max-width: calc(var(--col) + 2 * var(--frame-pad)); }
  .rail { display: none; }
  .main, .chrome-inner { grid-column: 1; }
  .framed-column { max-width: calc(var(--col) + 2 * var(--frame-pad)); padding-left: var(--frame-pad); }
}

/* phones (the explorer's own 30rem step): the bar scrolls with the page here, so anchor targets
   have nothing pinned to clear. The menu itself is the hamburger from 700px down, so its layout
   is stated once, above, and not again here. */
@media (max-width: 30rem) {
  /* Static, so the bar scrolls away on a narrow screen -- but `relative` rather than `static`, so
     it still makes a stacking context.  Without one, the analysis page's record heading
     (`position: relative; z-index: 1`) paints over the bar and the menu cannot be opened at all:
     measured at 360px on 2026-09-03, where a click on the button lands on the H1.
     Relative for the stacking context only; the sticky rule's `top: 0` moves nothing here. */
  .chrome { position: relative; z-index: 50; }
  html { scroll-padding-top: 15px; }
}

/* the privacy footer every explorer route ends with (2026-09-04, agentwatch decision 0019). Here
   rather than in explorer.css because Base.astro loads this file too and the footer is chrome, not
   a record view. A top rule and dull ink: a reader who scrolls to the end of a thread should see
   it, without it competing with the records above. */
.privacy {
  margin: 3rem 0 0;
  padding-top: 0.9rem;
  padding-bottom: 2.5rem;
  border-top: 1px solid var(--rule);
  color: var(--dull-foreground);
  font-size: 0.85rem;
  line-height: 1.5;
}
.privacy p { margin: 0; max-width: 68ch; }
