/* ══════════════════════════════════════════════════════════════════════════
   earl.ee — platform bar (Kanoniker)

   The one bar above every platform surface (DESIGN-SYSTEM.md: "The platform
   bar"). 44px, theme-STABLE on the --night-* constants — on a preview it sits
   above an app whose design the platform does not control and must read as
   *not part of it*. Exactly four zones: wordmark · place switcher ·
   context (previews only) · account. Left is where, right is who — the two
   menus never merge.

   The mark is NOT in this bar, and there is no zone for it. It is gold on an
   ink square and this ground IS ink: the square vanishes and what remains is
   a naked gold chevron sitting beside the switcher's real caret — two carets,
   one of them inert. The wordmark alone is unambiguous, and the browser tab
   already carries the mark four pixels above the bar (DESIGN-SYSTEM.md:
   "Why the mark is not in the bar", trap 4: the mark needs a ground that is
   not its own).

   Canon rules for this file
   - Mirrored byte-identically into every consumer (pre-commit hook, same
     mechanism as tokens.css; tools/sync-design-tokens.sh distributes). A
     consumer may inline it into a <style> in the <head> instead of linking
     it — the byte-equality check runs against the <style> content then
     (DESIGN-SYSTEM.md, "Inlining"). Contains no url(); keep it that way.
   - The bar only. The review dock (.pb-dock, .pb-dock-mark) lives in
     review-dock.css — one consumer renders it, so no other surface pays
     for it.
   - Requires tokens.css to be loaded first: every colour, font, radius,
     motion and focus value is a var(). The bar's own GEOMETRY (44px height,
     the 14px inset, control paddings, type sizes) is the platform-bar spec
     itself, taken at full fidelity from the reference — those literals are
     canon here, not improvisation in a consumer (Rule 01 still binds
     consumers).
   - Menus are native <details>/<summary> — no JavaScript required, which the
     www surface demands ("no JavaScript" is test-pinned there).
   - The caret is a CSS triangle, the onward arrow an inline SVG with
     stroke="currentColor": arrow glyphs (▾ ↗) are outside the shipped font
     subsets and degrade into specks (DESIGN-SYSTEM.md: "Glyphs"). ONE caret
     per bar — it belongs to the place switcher and to nothing else; the
     avatar opens its menu without one.

   Markup contract (rebuild per stack; dynamic parts differ per consumer):

     <header class="platform-bar">
       [zone 1 — the wordmark alone, no mark:]
       <a class="pb-mark" href="https://my.EXAMPLE">
         <span class="pb-wordmark">earl.ee</span>
       </a>
       [zone 2 — the label NAMES THE SURFACE YOU ARE ON (on a preview: the
        app's own name); the menu lists the places you are NOT on, and the
        current place is never among them:]
       <details class="pb-menu pb-switcher">
         <summary><span class="pb-switcher-label">Tools</span>
                  <span class="pb-caret" aria-hidden="true"></span></summary>
         <nav class="pb-menu-list">
           My Projects · Tools · Code · Account · Homepage — minus the current one
         </nav>
       </details>
       [zone 3 — state zone 2 cannot show. Previews: env badge + version.
        my.earl.ee: type and name of the thing the page is about, because
        zone 2 says only "my". Never the app name (zone 2 already said it),
        never a breadcrumb. Empty everywhere else (code, tools, account):]
       <span class="pb-env-badge">preview</span>
       <span class="pb-version">v1.2.3</span>
       <span class="pb-context"><span class="pb-context-type">Projekt</span> · building-x-website</span>
       <span class="pb-spacer"></span>
       [the onward link sits RIGHT of the spacer, beside the account: it is a
        way out, and ways out are on the right. Word first, arrow after — the
        arrow says "you are leaving", and that is said after the destination:]
       <a class="pb-onward" href="…" title="To the app page"><span class="pb-onward-label">
         To the app page</span>[arrow SVG]</a>                [i18n: preview.onward]
       [signed in:]
       <details class="pb-menu pb-menu--right pb-account">
         <summary class="pb-avatar" title="user@example.org">AD
           <span class="pb-avatar-dot" hidden></span></summary>
         <nav class="pb-menu-list">
           <span class="pb-menu-account">user@example.org</span>
           <span class="pb-menu-note" hidden>Session ends in 0:12</span>
           <a href="…">Account</a>
           <a href="…">Tokens</a>
           <span class="pb-menu-rule"></span>
           <a href="…">Sign out</a>
         </nav>
       </details>
       [signed out:] <a class="pb-signin" href="…">Sign in</a>
     </header>

   Narrow-width drop order (spec order; the px thresholds are this file's
   choice): version → onward label (the arrow stays) → wordmark.

   THE PLACE AND THE ACCOUNT ZONE NEVER DROP — not the place label, not to a
   caret alone. Those two are the answer to *where am I* and *how do I leave*,
   and a bar that has dropped both is a black stripe. The wordmark goes first
   because the URL bar is already saying earl.ee one line above it.
   ════════════════════════════════════════════════════════════════════════ */

/* The bar's PUBLIC INTERFACE — its height and its layer, named so a surface can
   reference them instead of copying them.

   These are not new numbers; they are the two literals below with a name. The
   bar keeps laying itself out with its own values. What changes is that a page
   which has to sit *under* the bar can now say so: `.sticky-under-bar` in
   components.css reads --pb-height, and no surface has to know that the bar is
   44px tall.

   The need was measured, not imagined: three surfaces (shape-ui,
   invite-service, introspection-viewer) had independently written
   `position: sticky; top: 0` for their filter field and were all three hidden
   behind the bar, because the bar is sticky at top 0 too and outranks them.
   Three surfaces reaching the same wrong answer is the proof that it was never
   a local question.

   --pb-z is published for completeness and is expressly NOT something a surface
   reaches for: the bar is always the topmost layer, and anything competing with
   it is a bug. `.sticky-under-bar` uses 10. */
:root {
  --pb-height: 44px;
  --pb-z: 100;
}

.platform-bar {
  position: sticky;          /* sticky reserves its height — the page below   */
  top: 0;                    /* starts at 44px by normal flow. Never fixed.   */
  z-index: 100;
  height: 44px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 14px;           /* reference inset — sub-ladder on purpose       */
  background: var(--night-surface);
  overflow: visible;         /* the menus drop below the bar                  */
}

/* A 44px bar whose contents can wrap is the clattering it exists to prevent. */
.platform-bar > * {
  flex: none;
  white-space: nowrap;
}

.platform-bar a {
  text-decoration: none;
}

.platform-bar :focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-control);
}

/* ── zone 1 · wordmark (the mark is not in this bar) ─────────────────────── */

.pb-mark {
  display: inline-flex;
  align-items: center;
  color: var(--night-ink);
}

.pb-wordmark {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--night-ink);
}

/* ── menus (shared) — native <details>, no script ────────────────────────── */

.pb-menu {
  position: relative;
}

.pb-menu > summary {
  list-style: none;
  cursor: pointer;
}
.pb-menu > summary::-webkit-details-marker {
  display: none;
}

.pb-menu-list {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 180px;
  padding: var(--space-sm) 0;
  background: var(--night-raised);
  border: 1px solid var(--night-line);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-lift);   /* a menu genuinely floats (Rule 04)      */
  display: flex;
  flex-direction: column;
  z-index: 101;
}

.pb-menu--right .pb-menu-list {
  left: auto;
  right: 0;
}

.pb-menu-list a {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--night-ink);
  padding: 8px 14px;
  transition: background var(--dur-state) ease-out;
}

.pb-menu-list a:hover {
  background: var(--night-line);
}

.pb-menu-rule {
  height: 1px;
  margin: var(--space-sm) 0;
  background: var(--night-line);
}

/* Non-interactive menu lines: the full account address, the expiry note.    */
.pb-menu-account,
.pb-menu-note {
  font: var(--text-meta);
  color: var(--night-muted);
  padding: 4px 14px;
}

.pb-menu-note {
  color: var(--night-fault);
}

/* ── zone 2 · place switcher ─────────────────────────────────────────────── */

/* The ONE flexible child — everything else is flex:none. On a preview this
   button carries the app's own name, and an arbitrarily long name must
   ellipsis rather than push the bar (DESIGN-SYSTEM.md: "the app name is the
   single flexible item"). It NARROWS; it never drops.                       */
.platform-bar > .pb-switcher {
  flex: 0 1 auto;
  min-width: 0;
}

.pb-switcher > summary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-width: 0;              /* so the label truncates, not the control      */
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--night-ink);
  background: var(--night-raised);
  border: 1px solid var(--night-line);
  border-radius: var(--radius-control);
  padding: 5px 10px;
  transition: border-color var(--dur-state) ease-out;
}

.pb-switcher > summary:hover {
  border-color: var(--night-line-strong);
}

.pb-switcher-label {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Drawn, never typed (▾ falls back to a speck). Never shrinks with the
   label — a caret compressed to a sliver is the speck it exists to avoid.   */
.pb-caret {
  flex: none;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--night-muted);
}

/* ── zone 3 · context — state zone 2 cannot show ─────────────────────────── */
/* previews: .pb-env-badge + .pb-version · my.earl.ee: .pb-context · else empty */

.pb-env-badge {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--env-preview);
  border-radius: var(--radius-pill);
  padding: 4px 10px;
}

.pb-version {
  font: var(--text-meta);
  color: var(--night-faint);
}

/* my.earl.ee only — "Projekt · <name>" / "App · <name>". Two tones in one line:
   the type is quiet, the name is the ink. Never the app name of a preview. */
.pb-context {
  flex: none;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--night-ink);
  white-space: nowrap;
}

.pb-context-type {
  color: var(--night-muted);
}

.pb-onward {
  display: inline-flex;
  align-items: center;
  gap: 6px;                            /* label, then arrow — DOM order, no reordering */
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--night-muted);
  transition: color var(--dur-state) ease-out;
}

.pb-onward:hover {
  color: var(--night-ink);
}

.pb-onward svg {
  width: 14px;
  height: 14px;
  display: block;
}

.pb-spacer {
  flex: 1;
}

/* ── zone 4 · account ────────────────────────────────────────────────────── */

.pb-avatar {
  position: relative;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--night-raised);
  border: 1px solid var(--night-line-strong);
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--night-muted);
  transition: color var(--dur-state) ease-out,
              border-color var(--dur-state) ease-out;
}

.pb-avatar:hover {
  border-color: var(--night-ink);
  color: var(--night-ink);
}

/* The avatar must never deform from a circle.                               */
.pb-account > .pb-avatar {
  flex: none;
}

/* Session about to expire: --night-fault, because --fault flips with the
   theme and disappears on the theme-stable night ground (the Rule-09 bug
   class the night constants exist to prevent). The menu carries the state
   in words (Rule 13) — the dot is never the only channel.                   */
.pb-avatar-dot {
  position: absolute;
  top: -2px;
  right: -2px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--night-fault);
  border: 2px solid var(--night-surface);
}

.pb-avatar-dot[hidden],
.pb-menu-note[hidden] {
  display: none;
}

/* Signed out: the state is a word, never an empty avatar.                   */
.pb-signin {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
  color: var(--night-ink);
  background: transparent;
  border: 1px solid var(--night-line-strong);
  border-radius: var(--radius-control);
  padding: 6px 14px;
  transition: border-color var(--dur-state) ease-out;
}

.pb-signin:hover {
  border-color: var(--night-ink);
}

/* ── 44px touch targets on a 28px control (Rule 07): invisible hit-area
      extension — the visual pill stays as specified. ──────────────────────── */

.pb-switcher > summary,
.pb-signin,
.pb-onward {
  position: relative;
}

.pb-switcher > summary::after,
.pb-signin::after,
.pb-onward::after,
.pb-avatar::after {
  content: "";
  position: absolute;
  inset: -9px;
}

/* ── narrow widths: fixed drop order, nothing wraps ──────────────────────────
      Three steps, and only three: version → onward label → wordmark. The
      place label and the account zone are NOT on this list at any width —
      they answer *where am I* and *how do I leave*, and a bar that has
      dropped both is a black stripe.                                        */

@media (max-width: 900px) {
  .pb-version { display: none; }
}

@media (max-width: 760px) {
  .pb-onward-label { display: none; }   /* the arrow stays, with its title   */
}

/* Zone 1 IS the wordmark now, so the whole link goes — an emptied <a> would
   stay in the tab order and flash a focus ring around nothing.              */
@media (max-width: 460px) {
  .pb-mark { display: none; }
}
