/* The v2 app shell — workflow sidebar + context bar. Shared by every spine screen.
 *
 * ## Chrome is INK `#1C242B`, ruled 2026-08-22 by Bevan, reversing the 21 Aug paper ruling
 *
 * ⚠ **Fourth chrome ruling, third reversal.** 13 Aug (r6) marine → ink; 21 Aug ink → paper;
 * 22 Aug back to ink. Bevan, on the screenshot pairs: *"THE SIDE TABS NOT PASSED THEY NEED TO
 * BE THE SAME COLOUR AS DESIGN."*
 *
 * ⚠ **The 21 Aug ruling was made on a claim that was false, and this is the record of it.**
 * Both `CLAUDE.md` and `START-HERE.md` said *"the mockup has always rendered `paper`"*, and the
 * 21 Aug note added *"verified in a browser against the mockup"*. **The design project's own
 * captures render the rail `#1C242B` on every one of its 32 screens.** It was logged as E14 on
 * 22 Aug after the pixel was measured rather than read off a file, and Bevan answered it the
 * same day. **A ruling is only as good as the reading under it** — this one survived a day.
 *
 * ## The values are MEASURED, not transcribed
 *
 * Sampled from `reference/design-system/design_handoff_call_up_and_quote/screens/`, because a
 * transcription is what produced the claim above. Every one appears in the captures:
 *
 *   `#1C242B` rail · `#394046` the active item's block · `#FFFFFF` its text ·
 *   `#9AA6AE` a resting item · `#77808A` a group heading · `#5E6B75` a dim numeral ·
 *   `#9FE0F0` the "Pro" in the wordmark and the active numeral
 *
 * This matches the `ink` variant `AppChrome.jsx` already ships and `CLAUDE.md` already records,
 * and it adds the two that record did not carry: the active block and its text.
 *
 * `AppChrome.jsx` ships all three variants on one `chrome` prop, so none of them is a departure
 * from the design; which one runs is the ruling. `marine` is `bg #173B53 / label #6E8798 /
 * txt #A5B9C7 / num #9FE0F0`. `#24567E` remains retired artwork and is not introduced.
 *
 * ## ⚠ Two rules were reaching past the tokens again, and one of them was a live defect
 *
 * The 21 Aug header records that the previous ruling found five bypasses, *"every one invisible
 * on a light ground"*. Two were introduced or left behind by that same change:
 *
 *   * `.rail__brand` took `var(--fc-ink)` — correct on a pale rail, **the rail's own colour on
 *     a dark one**, so the wordmark would have vanished into the background.
 *   * `.rail__fallback` kept `#9AA6AE`, `rgba(255,255,255,0.18)` and `#fff` — **dark-rail
 *     literals left in place when the rail went pale.** Since 21 Aug the "Switch to Classic"
 *     link has carried a white dashed border at 18% opacity on a `#F7F6F2` ground: invisible,
 *     on the one control that leads to the other nine screens. It shipped that way for a day.
 *
 * **Both are tokens now.** The lesson is the header's own, unchanged and now twice-earned: a
 * token layer with bypasses is a token layer no change has tested, and the bypasses are only
 * ever visible from the side the chrome is *not* currently on.
 */

:root {
  /* ── the rail ── */
  --chrome-surface:     var(--fc-ink);         /* #1C242B — measured off the design's captures */
  --chrome-border:      transparent;           /* a dark rail needs no edge against a light page;
                                                  the pale one did, which is why this is a token */
  --chrome-ink:         #9AA6AE;               /* resting item — no palette token names it; the
                                                  design system publishes no on-ink text ramp */
  --chrome-ink-strong:  var(--fc-white);       /* the active item */
  --chrome-ink-quiet:   #77808A;               /* group headings — likewise unnamed */
  --chrome-hover-bg:    rgba(255, 255, 255, 0.05);
  /* ⚠ **`#394046` was measured off a capture and it was exactly right — and exactly the
     wrong SHAPE.** `AppChrome.jsx` sets `activeBg: rgba(255,255,255,0.13)`, and 13% white over
     `#1C242B` composites to `rgb(57,64,70)`, which is `#394046` to the byte. So the pixel was
     read correctly and the rule behind it was invisible: a flat hex is only right while the rail
     is this exact colour, and this rail has changed colour four times in ten days. Source form,
     so the next ruling carries it. */
  --chrome-active-bg:   rgba(255, 255, 255, 0.13);
  --chrome-accent:      var(--fc-sky);         /* #9FE0F0 — the "Pro", and the active numeral */
  --chrome-num-dim:     var(--fc-steel);       /* #5E6B75 — resting numeral, measured */
  /* ── the quote-total panel at the foot of the rail ── */
  /* ⚠ **Both of these were ours, not the design's, and both were visible.** `AppChrome.jsx`
     draws the quote-total card at `cardBg: rgba(255,255,255,0.08)` with `cardBr: 'none'`; this
     had it at 5% behind a 12% white hairline. Dimmer card, and an edge the design does not
     draw. The border is the whole shorthand rather than a colour, because the paper variant's
     is `1px solid #E9E7E1` and a colour token cannot say `none`. */
  --chrome-panel-bg:     rgba(255, 255, 255, 0.08);
  --chrome-panel-border: none;
  --chrome-panel-label:  var(--fc-sky);
  --chrome-panel-val:    var(--fc-white);
  --chrome-panel-sub:    #9AA6AE;
  /* ── the context bar ── the bar is on the PAGE, not the rail, and does not move with it ── */
  --chrome-fallback-line:       rgba(255, 255, 255, 0.18);
  --chrome-fallback-line-hover: rgba(255, 255, 255, 0.4);
  --chrome-bar:         rgba(250, 250, 248, 0.92);
}

.shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
  background: var(--fc-paper);
}
.shell__main { min-width: 0; }

/* ── sidebar ─────────────────────────────────────────────────────────────── */

.rail {
  background: var(--chrome-surface);
  color: var(--chrome-ink);
  border-right: 1px solid var(--chrome-border);
  padding: 18px 14px;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }

/* ⚠ **The design's lockup is a 30px icon beside the wordmark, and we had neither the icon nor
   the right type.** `AppChrome.jsx`: a flex row, `gap: 10px`, `padding: 6px 4px 0`,
   `margin-bottom: 18px`, the mark at `height: 30px`, and the wordmark at **800 15px/1,
   `-0.01em`** — this file had `17px` and `-0.015em`, both measured off a capture that is 1.37×
   scale. **A number read off a scaled screenshot is a number in the screenshot's units.**

   The mark is `ui/brand/mark-on-navy.svg`, which is **byte-identical** to the design's
   `assets/brand/icon-for-navy.svg`. Served from `ui/`, which is the static root — the repo's
   top-level `brand/` is not served and a path into it would 404. */
.rail__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 4px 0;
  margin-bottom: 18px;
}
.rail__brand-icon { height: 30px; display: block; }
.rail__brand-sub {
  display: block;
  font: 400 11px/1.4 var(--font-mono);
  color: var(--chrome-ink-quiet);
  letter-spacing: 0;
  margin-top: 3px;
}
.rail__brand-name {
  font: 800 15px/1 var(--font-body);
  letter-spacing: -0.01em;
  /* ⚠ **`var(--fc-ink)` here was the rail's own colour once the rail went dark.** A wordmark
     that matches its background is the bypass this file's header is about. The design hard-codes
     `#fff`, which is the same thing one theme along — its own paper variant would draw a white
     wordmark on `#F7F6F2`. Tokenised, so ours does not. */
  color: var(--chrome-ink-strong);
}
/* "Pro" carries the accent, as it does in `AppChrome.jsx` — the only place the wordmark is
   two colours, and the half that says which product this is. */
.rail__brand-pro { color: var(--chrome-accent); }
/* ⚠ **"quote spine" was removed on 22 Aug and put back the same day. Read this before touching
   it again.**

   It came out because the design's lockup is an icon and a wordmark, full stop, and R7 says copy
   it exactly. **That was the wrong reading of R7 and the design's own author said so:** *"the
   design's lockup doesn't have one, but that makes it an omission in my documentation, not an
   instruction. A live user-visible element shouldn't come out because a handoff doc didn't
   mention it."*

   **The rule this leaves behind is worth more than the sub-line.** A handoff document is a
   description of a mock, and a mock is silent about everything it never had. **Silence is not an
   instruction to delete.** R7 governs what is *in* the thing being copied — re-ordering its rows,
   renaming its labels, tidying its columns. It says nothing about what a working product has and
   a prototype does not, and reading it that way turns every gap in a document into a demolition
   order.

   ⚠ **Two more removals were within one reading of the same mistake and did NOT happen**: the
   thirteen media queries (the bundle said *"ask before inventing it"*, and its author has since
   corrected that outright — *"do not revert them to match this document"*) and `.rail__fallback`,
   *"Switch to Classic"*, which appears in no mock and is the only way to the other nine screens.

   **If it goes, it goes because Bevan asks.** */

.rail__group { margin-bottom: 14px; }
.rail__heading {
  font-family: var(--font-body);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--chrome-ink-quiet);
  padding: 0 12px 6px;
}
.rail__items { display: flex; flex-direction: column; gap: 2px; }

.rail__item {
  display: flex;
  align-items: center;
  gap: 9px;
  border: none;
  background: transparent;
  color: var(--chrome-ink);
  font-family: var(--font-body);
  font-size: 13.5px;
  font-weight: 500;
  padding: 8px 12px;
  border-radius: var(--radius-control);
  cursor: pointer;
  text-align: left;
  width: 100%;
  text-decoration: none;
}
.rail__item:hover { background: var(--chrome-hover-bg); color: var(--chrome-ink-strong); }
.rail__item--active {
  background: var(--chrome-active-bg);
  color: var(--chrome-ink-strong);
  font-weight: 700;
}
/* A screen that exists in the design and not yet in the build. **Named, not hidden** — a
   sidebar that silently omits half the product tells the reader the product is half the size. */
.rail__item--todo { opacity: 0.45; cursor: default; }
.rail__item--todo:hover { background: transparent; color: var(--chrome-ink); }

.rail__n {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--chrome-num-dim);
  width: 16px;                 /* the design's, not 12px — the rail numbers reach 31 */
  flex: none;
}
.rail__item--active .rail__n { color: var(--chrome-accent); }

.rail__total {
  margin-top: auto;
  background: var(--chrome-panel-bg);
  border: var(--chrome-panel-border);
  border-radius: var(--radius-card);
  padding: 12px 14px;
}
.rail__total-k {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--chrome-panel-label);
}
.rail__total-v {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 600;
  color: var(--chrome-panel-val);
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.rail__total-sub { font-size: 11.5px; color: var(--chrome-panel-sub); }

/* ── context bar ─────────────────────────────────────────────────────────── */

.topbar {
  background: var(--chrome-bar);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--fc-line);
  padding: 12px 32px;
  display: flex;
  align-items: center;
  gap: 16px;
  position: sticky;
  top: 0;
  z-index: 10;
  min-height: var(--topbar-h);
}
.topbar__job {
  font-family: var(--font-body);
  font-size: 13.5px;
  font-weight: 600;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topbar__job span { color: var(--fc-mute); font-weight: 500; }
/* Contract A §1.4–§1.5 — the job line the server answers with (`#chrome_job`, never composed
   here) and `Close job` beside it: a context release only. Provenance: the mock's AppChrome
   masthead (ui_kits/fencecalc-pro/screens/AppChrome.jsx @ r30). */
.topbar__job #chrome_job { color: var(--fc-ink); font-weight: 600; }
.topbar__job #chrome_job[data-job=""] { color: var(--fc-mute); font-weight: 500; }
.topbar__close {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--fc-steel);
  background: var(--fc-white);
  border: 1px solid var(--fc-line);
  border-radius: 7px;
  padding: 2px 8px;
  margin-left: 8px;
  cursor: pointer;
  white-space: nowrap;
  vertical-align: middle;
}
.topbar__close:hover { border-color: var(--fc-line-strong); }
/* Contract B §1.7 — the save signal beside the job line: text only, three states, the reason in
   user-facing language. Placement and the reason wording are Design's to confirm (request r2
   item 5); nothing here is a toast, a button or a dirty marker. */
.topbar__save {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fc-mute);
  white-space: nowrap;
}
.topbar__save[data-state="saved"] { color: var(--fc-green); }
.topbar__save[data-state="failed"],
.topbar__save[data-state="conflict"] { color: var(--fc-red); font-weight: 600; }
.topbar__spacer { flex: 1; }

@media (max-width: 900px) {
  /* Owner ruling 3: C-3 measured active-pill overlap at 390/768/900; desktop stays content-box. */
  .rail__item { box-sizing: border-box; }
  .shell { grid-template-columns: 1fr; }
  .rail { position: static; height: auto; flex-direction: row; flex-wrap: wrap; gap: 8px; }
  .rail__total { margin-top: 0; }
}

/* The way back to the built interface. Quiet, and always visible — v2 is the quote spine and
   the other nine screens live only in `ui/`. */
/* ⚠ **These three were raw dark-rail literals and they stayed raw when the rail went pale** —
   a white dashed border at 18% on `#F7F6F2` is nothing at all, on the one control that reaches
   the other nine screens. Tokens now, so the next ruling moves them with everything else. */
.rail__fallback { display: block; margin: 18px 14px 0; padding: 8px 10px;
                  font-size: 12px; color: var(--chrome-ink); text-decoration: none;
                  border: 1px dashed var(--chrome-fallback-line); border-radius: 8px; }
.rail__fallback:hover { color: var(--chrome-ink-strong);
                        border-color: var(--chrome-fallback-line-hover); }

/* Development integration recovery states; independent Design review pending. */
.topbar:has(#chrome_save_recovery:not([hidden])),
.topbar:has(.topbar__save[data-state="failed"]),
.topbar:has(.topbar__save[data-state="conflict"]) { flex-wrap: wrap; }
.topbar__save[data-state="failed"], .topbar__save[data-state="conflict"] {
  white-space: normal; overflow-wrap: anywhere; flex: 1 1 200px;
}
#chrome_save_recovery:not([hidden]) {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex-basis: 100%; order: 2;
}
