/* ---------------------------------------------------------------------------
   R2A3. The design system from docs/mockup-manager-dashboard.html, applied to
   the real application.

   Two tokens differ from the mockup, because the mockup was never contrast
   tested and four of its fifteen text pairs failed WCAG AA:

     --muted  #77837f -> #646e6a   was 3.93:1 on white, 3.40:1 on --hair-2
     --warn   #9a6d14 -> #8f6513   was 4.02:1 on --warn-bg

   Every text pair in this file now clears 4.5:1. Darkening either token
   further is fine; lightening them is not.

   Brand: forest #18342f, bronze gold #604a24, Inter for prose and
   IBM Plex Mono for anything a human reads as a code or a figure.
--------------------------------------------------------------------------- */

:root {
  --forest:   #18342f;
  --forest-2: #22463f;
  --forest-3: #2e5a51;
  --gold:     #604a24;
  --gold-2:   #8a6b32;

  --ink:      #16201e;
  --ink-2:    #485652;
  --muted:    #646e6a;
  --hair:     #e2e3dc;
  --hair-2:   #eeefe8;
  --bg:       #f5f5f0;
  --card:     #ffffff;

  --good:     #2f6a4f;  --good-bg: #e6f0e9;
  --warn:     #8f6513;  --warn-bg: #faefd7;
  --crit:     #a0392b;  --crit-bg: #f9e5e1;
  --info:     #2b5670;  --info-bg: #e5edf2;

  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Consolas, monospace;
  --sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* --------------------------------- shell --------------------------------- */

.shell { display: grid; grid-template-columns: 186px 1fr; min-height: 100vh; }

.side {
  background: var(--forest); color: #dfe9e5;
  padding: 16px 0 16px; display: flex; flex-direction: column; gap: 16px;
  /* Pinned to the viewport, like the reference: the identity card stays at
     the bottom of the screen, not the bottom of a page-length column. */
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  scrollbar-width: none;
}
.side::-webkit-scrollbar { display: none; }
.side .brand {
  padding: 0 16px 14px; border-bottom: 1px solid var(--forest-3);
  display: flex; flex-direction: column; gap: 2px;
}
.side .brand .n { font-weight: 700; font-size: 15px; letter-spacing: -.01em; color: #fff; }
.side .brand .t { font-size: 10.5px; color: #8fb3a9; letter-spacing: .04em; }

.nav { display: flex; flex-direction: column; gap: 1px; padding: 0 8px; }
.nav a {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 9px 11px; border-radius: 3px; color: #c3d6d0;
  text-decoration: none; font-size: 13.5px;
}
.nav a:hover { background: var(--forest-2); color: #fff; }
.nav a.on { background: var(--forest-3); color: #fff; font-weight: 600; }
.nav .sep { height: 1px; background: var(--forest-3); margin: 8px 11px; }

.side .foot { margin-top: auto; padding: 0 16px; font-size: 11.5px; color: #8fb3a9; }
.side .foot a { color: #c3d6d0; }

.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 14px 22px; background: var(--card); border-bottom: 1px solid var(--hair);
}
.topbar h1 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.012em; color: var(--ink); }
.topbar .when { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.who { margin-left: auto; display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-2); }
.who .av {
  width: 26px; height: 26px; border-radius: 50%; background: var(--gold); color: #fff;
  display: grid; place-items: center; font-size: 11px; font-weight: 600;
}
.who .role { font-family: var(--mono); font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }

/* The role switch. Quiet on purpose: it sits beside the account name all day
   and only one account in the building ever sees it. */
.topbar .switch { margin: 0; }
.topbar .switch button {
  font: inherit; font-size: 12px; cursor: pointer;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--hair); background: var(--bg); color: var(--ink-2);
}
.topbar .switch button:hover { border-color: var(--gold); color: var(--ink); }

.page { padding: 20px 22px 60px; display: flex; flex-direction: column; gap: 20px; }

/* ------------------------------- headings -------------------------------- */

h2 {
  margin: 4px 0 0; font-size: 12px; font-weight: 600; letter-spacing: .13em;
  text-transform: uppercase; color: var(--gold); font-family: var(--mono);
}
h3 { margin: 0 0 6px; font-size: 14px; font-weight: 600; color: var(--ink); }

/* --------------------------------- tiles --------------------------------- */

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
.tile {
  background: var(--card); border: 1px solid var(--hair); border-radius: 4px;
  padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; position: relative;
}
.tile .k, .tile .lab { font-size: 11.5px; color: var(--muted); font-weight: 500; line-height: 1.35; }
.tile .v, .tile .num {
  font-size: 26px; font-weight: 700; line-height: 1.05; letter-spacing: -.025em;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.tile .foot { font-size: 11px; color: var(--muted); font-family: var(--mono); }
.tile.zero { background: var(--good-bg); border-color: #c6ddcd; }
.tile.zero .v, .tile.zero .num { color: var(--good); }
.tile .rule { position: absolute; left: 0; top: 0; bottom: 0; width: 3px; border-radius: 4px 0 0 4px; }

/* -------------------------------- panels --------------------------------- */

.panel { background: var(--card); border: 1px solid var(--hair); border-radius: 4px; overflow: hidden; }
.panel > table { border: 0; }
.phead {
  padding: 10px 14px; border-bottom: 1px solid var(--hair-2); background: var(--hair-2);
  display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
}
.phead b { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.phead .s { font-size: 11.5px; color: var(--muted); }
.scroll { overflow-x: auto; }

/* -------------------------------- tables --------------------------------- */

table {
  width: auto; max-width: 100%; border-collapse: collapse; font-size: 13px;
  background: var(--card); border: 1px solid var(--hair); border-radius: 4px;
}
table.wide { width: 100%; }
th {
  text-align: left; font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); font-weight: 600; padding: 8px 14px;
  border-bottom: 1px solid var(--hair-2); background: var(--hair-2);
}
td { padding: 9px 14px; border-bottom: 1px solid var(--hair-2); color: var(--ink-2); vertical-align: top; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: #fbfbf8; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); }
td a { color: var(--forest-3); font-weight: 500; }
.doc { font-family: var(--mono); font-weight: 600; color: var(--forest); }

/* --------------------------------- chips --------------------------------- */

.pill, .chip {
  display: inline-block; font-family: var(--mono); font-size: 9.5px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; padding: 2px 6px;
  border-radius: 2px; line-height: 1.6; background: var(--hair-2); color: var(--muted);
  border: 0; white-space: nowrap;
}
.pill.ok,   .chip.ok   { background: var(--good-bg); color: var(--good); }
.pill.warn, .chip.warn { background: var(--warn-bg); color: var(--warn); }
.pill.crit, .chip.crit { background: var(--crit-bg); color: var(--crit); }
.pill.info, .chip.info { background: var(--info-bg); color: var(--info); }

/* --------------------------------- forms --------------------------------- */

form.card {
  background: var(--card); border: 1px solid var(--hair); border-radius: 4px;
  padding: 16px 18px; max-width: 640px;
}
/* Mono and uppercase reads well on "SUPPLIER" and badly on a sentence, and
   several labels here are sentences. Mono caps stay on table headers and band
   headings, where the text is always short. */
label {
  display: block; margin: 12px 0 4px; font-size: 12.5px; font-weight: 600;
  color: var(--ink-2); line-height: 1.45;
}
input[type=text], input[type=email], input[type=password], input[type=file], select, textarea {
  width: 100%; padding: 8px 10px; border: 1px solid var(--hair); border-radius: 3px;
  font: inherit; font-size: 14px; background: #fff; color: var(--ink);
}
textarea { font-family: var(--mono); font-size: 12.5px; line-height: 1.7; }
input:hover, select:hover, textarea:hover { border-color: #cfd0c7; }

button {
  background: var(--forest); color: #fff; border: 0; border-radius: 3px;
  padding: 9px 16px; font: inherit; font-size: 13.5px; font-weight: 500;
  cursor: pointer; margin-top: 12px; min-height: 38px;
}
button:hover { background: var(--forest-2); }
button.secondary { background: transparent; color: var(--forest); border: 1px solid var(--hair); }
button.secondary:hover { background: var(--hair-2); }
td button, td button.secondary { margin-top: 0; padding: 5px 10px; min-height: 32px; font-size: 12px; }
/* A full-width date input inside a table cell doubles the row height. */
td form { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
td input[type=text] { width: auto; max-width: 118px; padding: 5px 8px; font-size: 12px; font-family: var(--mono); }
th:last-child, td:last-child { white-space: nowrap; }

a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--gold-2); outline-offset: 2px;
}

/* -------------------------------- flashes -------------------------------- */

.flash {
  padding: 10px 14px; border-radius: 3px; margin: 0;
  border: 1px solid; font-size: 13.5px;
}
.flash-ok    { background: var(--good-bg); border-color: #c6ddcd; color: var(--good); }
.flash-error { background: var(--crit-bg); border-color: #e8c9c3; color: var(--crit); }

/* Louder than an error, because it is not about what you just did: it stays on
   every manager screen until somebody changes a shipped password. A left bar
   rather than a brighter red, so it reads as standing rather than as a shout. */
.flash-crit {
  background: var(--crit-bg); color: var(--crit);
  border-color: #e8c9c3; border-left: 4px solid var(--crit);
}
.flash-crit a { color: var(--crit); }

/* --------------------------------- misc ---------------------------------- */

.muted { color: var(--muted); font-size: 12.5px; }
.page > p { margin: 0; }
img { max-width: 100%; height: auto; }

/* --------------------------------- login --------------------------------- */

.login-page {
  max-width: 380px; margin: 0 auto; padding: 70px 20px;
  display: flex; flex-direction: column; gap: 14px;
}
.login-page .brand { display: flex; flex-direction: column; gap: 2px; }
.login-page .brand .n { font-size: 22px; font-weight: 700; letter-spacing: -.02em; color: var(--forest); }
.login-page .brand .t { font-size: 12px; color: var(--muted); }
.login-page form.card { max-width: none; }

/* ------------------------------ responsive -------------------------------
   The original roll-out's strip layout lived here at max-width 820px, and it
   survived unnoticed under the newer 760px rail rules: between 760 and 820 it
   removed the sidebar column outright, and below 760 its row-direction flex
   scattered the rail's children sideways out of the 64px column -- the owner
   watched the sidebar vanish, reappear, and come back empty. The rail block
   further down is the one responsive layout now; only the padding tweaks
   were worth keeping. */

@media (max-width: 820px) {
  .page { padding: 16px 14px 50px; }
  .topbar { padding: 12px 14px; }
}

/* --------------------------------- print --------------------------------- */

/* A4 with 12mm margins leaves 273mm of height to divide between two documents. */
@page { size: A4; margin: 12mm; }

@media print {
  /* Never `form` here. A purchase order renders its values inside a form, and
     hiding every form prints the document blank. Anything that should vanish
     asks for it by name with .noprint. */
  .side, .topbar, .flash, .noprint { display: none; }
  body { background: #fff; }
  .page { padding: 0; }

  /* A table crossing a page break repeats its headings. */
  thead { display: table-header-group; }
  tr, .tile { page-break-inside: avoid; }

  /* One printable document. */
  .sheet {
    page-break-inside: avoid;
    position: relative;
  }
  .sheet + .sheet { page-break-before: always; }

  /* The print-only letterhead. .topbar is hidden, and an unheaded purchase
     order is not a document. */
  .sheet-head { display: block !important; }

  /* Two documents on one A4 page: 273mm of usable height, a 9mm gutter, so
     132mm each, with a cut line between them. */
  .twoup { display: block; page-break-inside: avoid; }
  .twoup > .sheet {
    height: 132mm;
    overflow: hidden;
    page-break-before: auto;
    page-break-inside: avoid;
  }
  .twoup > .sheet + .sheet {
    margin-top: 9mm;
    padding-top: 9mm;
    border-top: 1px dashed #999;   /* cut line */
    page-break-before: auto;
  }
}

/* The letterhead exists only on paper. */
.sheet-head { display: none; }

/* ------------------------------- filter bar ------------------------------ */

.filters {
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--hair); border-radius: 4px;
  padding: 12px 14px;
}
.filters span { display: flex; flex-direction: column; }
.filters label { margin: 0 0 4px; }
.filters input[type=text] { width: 240px; }
.filters select { width: auto; min-width: 170px; }
.filters button { margin-top: 0; }
.filters .check { justify-content: flex-end; }
.filters .check label { display: flex; align-items: center; gap: 6px; margin: 0 0 9px; font-weight: 500; }
.filters .check input { width: auto; }
.filters .clear { align-self: center; font-size: 12.5px; color: var(--muted); margin-bottom: 9px; }

/* Material picker: a floating list of matches under the search box. */
.picker-results {
  position: absolute; top: 100%; left: 0; z-index: 5; margin-top: 2px;
  width: 320px; max-height: 220px; overflow-y: auto;
  background: var(--card); border: 1px solid var(--hair); border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,.08);
}
.picker-results button {
  display: block; width: 100%; text-align: left; border: 0; border-radius: 0;
  background: transparent; color: var(--ink); padding: 6px 10px; margin: 0; font-size: 13px;
}
.picker-results button:hover { background: var(--hair-2, var(--hair)); }

.summary { margin: 0; font-size: 13px; color: var(--muted); }
.summary b { color: var(--ink); font-size: 15px; font-variant-numeric: tabular-nums; }

/* A retired row is still readable, just plainly not current. */
tr.retired td { color: var(--muted); background: #fafaf7; }
tr.retired td.strong { text-decoration: line-through; text-decoration-color: var(--hair); }
td.strong { color: var(--ink); font-weight: 500; }

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.grid2 span { display: block; min-width: 0; }
@media (max-width: 620px) { .grid2 { grid-template-columns: 1fr; } .filters input[type=text] { width: 100%; } }

.checks { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 2px 0 4px; }
.checks label { display: flex; align-items: center; gap: 6px; margin: 0; font-weight: 500; font-size: 13px; color: var(--ink-2); }
.checks input { width: auto; }
td .pill + .pill { margin-left: 3px; }

/* Two stacked forms in one action cell need breathing room. */
td form + form { margin-top: 5px; }
td input[type=text][name=unit_cost], td input[type=text][name=srp] { max-width: 86px; text-align: right; }

/* ------------------------------ price table ------------------------------ */
/* Grouped rows: a material with two suppliers spans its name cell, so the
   eye reads one item and two offers instead of the same name twice. The
   hairline above each group does the separating that the repeated name
   used to do. */
.prices tr.group td { border-top: 1px solid var(--hair); }
.prices tbody tr:first-child td { border-top: 0; }
.prices td.money { font-weight: 600; color: var(--ink); }
.prices td.money.best { color: var(--good); }
.prices td[rowspan] { vertical-align: top; }
.prices .s { font-size: 11.5px; color: var(--muted); }

/* -------------------------------- motion ---------------------------------
   One duration, one curve, applied only to the properties hover and focus
   already change. Nothing moves that was not already changing; it just stops
   changing instantaneously, which is what read as stiffness. */

:root { --ease: cubic-bezier(.25, .6, .3, 1); --quick: .15s; }

a, button,
input, select, textarea,
.nav a, .pill, .chip, .tile, .card {
  transition:
    background-color var(--quick) var(--ease),
    border-color     var(--quick) var(--ease),
    color            var(--quick) var(--ease),
    box-shadow       var(--quick) var(--ease),
    transform        var(--quick) var(--ease),
    opacity          var(--quick) var(--ease);
}
tbody tr td { transition: background-color var(--quick) var(--ease); }

/* A press should feel like one. */
button:active { transform: translateY(1px); }

/* The pointer resting on a tile answers "is this clickable-ish" quietly. */
.tile:hover { border-color: #d3d4ca; box-shadow: 0 1px 6px rgba(22, 32, 30, .06); }

/* A flash arrives; arriving things move in. The keyframes stay tiny so the
   same rule reads fine on a 419 page and on the dashboard. */
@keyframes flash-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
.flash { animation: flash-in .25s var(--ease); }

/* Live results mid-refresh: perceptibly pending, still readable. The delay
   keeps sub-150ms responses from flickering the table at all. */
[data-live].busy { opacity: .55; transition: opacity .12s var(--ease) .15s; }
[data-live] { transition: opacity .12s var(--ease); }

@media (prefers-reduced-motion: reduce) {
  a, button, input, select, textarea, .nav a, .pill, .chip, .tile, .card,
  tbody tr td, [data-live] {
    transition: none;
    animation: none;
  }
  .flash { animation: none; }
  button:active { transform: none; }
}

/* --------------------------- side-by-side review --------------------------
   The transcribed table on the left, the photographed sheet on the right.
   The photo sticks while the table scrolls, because the whole job here is
   reading one against the other. */

.sheetnav {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--hair); border-radius: 4px;
  padding: 10px 14px;
}
.sheetnav .arrow { font-size: 13px; font-weight: 500; color: var(--forest-3); white-space: nowrap; }
.sheetnav .arrow.off { color: var(--hair); }
.sheetnav .where { flex: 1; text-align: center; font-size: 13px; color: var(--muted); }
.sheetnav .where b { color: var(--ink); }

.review { display: grid; grid-template-columns: minmax(0, 1fr) minmax(260px, 36%); gap: 14px; align-items: start; }
.review-photo {
  position: sticky; top: 14px;
  background: var(--card); border: 1px solid var(--hair); border-radius: 4px;
  padding: 10px; max-height: calc(100vh - 90px); overflow: auto;
}
.review-photo img { width: 100%; display: block; border-radius: 2px; }
.review-photo .s { margin: 8px 0 0; font-size: 11.5px; }

/* The item name gets the width the money inputs do not need. Fixed layout,
   because auto layout hands the money columns the slack and folds the item
   name to one word per line. */
.review-table table { table-layout: fixed; }
.review-table th:nth-child(1) { width: 36px; }  /* the sheet-order number */
.review-table th:nth-child(2) { width: 31%; }
.review-table th:nth-child(3) { width: 8%; }
.review-table th:nth-child(4) { width: 16%; }
.review-table th:nth-child(5) { width: 16%; }
.review-table td.n { font-family: var(--mono); font-size: 10.5px; color: var(--muted); }
.review-table td { vertical-align: middle; }
/* Deliberately "acts", not the generic "td.actions": this column wraps a
   money input and a button in a narrow, fixed-width cell, which needs
   normal white-space and its own flex sizing below -- td.actions's
   nowrap/right-align/width:1% would fight that. Keep the two classes split. */
.review-table td.acts, .review-table td:last-child { white-space: normal; }
.review-table td.acts form { display: inline-flex; gap: 6px; align-items: center; margin: 0 4px 0 0; flex-wrap: wrap; }
.review-table td.acts form { width: 100%; }
.review-table td.acts input[type=text] {
  flex: 1 1 90px; width: auto; min-width: 0; max-width: 170px;
  margin: 0; min-height: 34px; font-size: 12.5px;
}
.review-table td.acts button { margin: 0; }
.review-table input.money {
  width: 100%; max-width: 96px; margin: 0; min-height: 34px; padding: 6px 8px;
  text-align: right; font-family: var(--mono); font-size: 12px;
}
tr.flagged td { background: var(--warn-bg); }
tr.flagged:hover td { background: #f5e8c9; }
.review-table .s { display: block; font-size: 11.5px; color: var(--muted); font-weight: 400; }

@media (max-width: 700px) {
  .review { grid-template-columns: 1fr; }
  .review-photo { position: static; max-height: none; }
}

/* ------------------------------- soft pass -------------------------------
   The owner's verdict on the first design roll-out: "edges felt sharp and
   generic." Reference: soft rounded cards, line icons, filled inputs, real
   weight on the numbers. Same forest palette, same layout; this section only
   re-cuts the edges, so it deliberately overrides radii and paddings set
   above rather than editing thirty rules in place. */

:root { --r-lg: 14px; --r-md: 10px; --display: "Sora", var(--sans); }

/* Display face for the few things that should not look like paragraph text:
   the brand, screen titles, and the big numbers on tiles. */
.topbar h1, .brand .n, .tile .v, .tile .num { font-family: var(--display); }
.topbar h1 { font-weight: 700; }

.card, form.card, .tile, .panel, .filters, .sheetnav, .review-photo, .flash { border-radius: var(--r-lg); }

/* border-collapse:collapse silently discards border-radius, which is why the
   4px above never showed. separate + zero spacing keeps the exact same look
   and lets the corners actually round. */
table { border-collapse: separate; border-spacing: 0; border-radius: var(--r-lg); overflow: hidden; }
.panel > table, .panel .scroll table { border-radius: 0; border: 0; }

input[type=text], input[type=email], input[type=password], input[type=file], select, textarea {
  border-radius: var(--r-md); padding: 10px 12px; background: #fbfbf8;
}
input:focus, select:focus, textarea:focus { background: #fff; border-color: var(--gold-2); }

button { border-radius: var(--r-md); padding: 10px 18px; }
td button, td button.secondary { border-radius: 8px; }

.pill, .chip { border-radius: 5px; }

/* Sidebar: icons beside labels, soft active pill, a slide on hover so the
   pointer gets an answer. */
.nav { padding: 0 10px; gap: 2px; }
.nav a { justify-content: flex-start; gap: 10px; border-radius: var(--r-md); padding: 9px 12px; }
.nav a .ic { display: grid; place-items: center; opacity: .75; }
.nav a:hover { transform: translateX(2px); }
.nav a.on .ic, .nav a:hover .ic { opacity: 1; }

/* Row actions and the filter bar's Clear: a quiet chip instead of a bare
   word, so "Edit" reads as a control rather than a leftover. */
.act, .filters .clear {
  display: inline-block; padding: 4px 12px; border: 1px solid var(--hair);
  border-radius: 999px; font-size: 12px; font-weight: 500;
  color: var(--forest-3); background: var(--card); text-decoration: none;
  line-height: 1.6; white-space: nowrap;
}
.act:hover, .filters .clear:hover { border-color: var(--forest-3); background: var(--hair-2); }

/* The filter bar lines up on one baseline: every control the same height,
   every bottom margin the same size. */
.filters { align-items: end; gap: 14px; }
.filters input[type=text], .filters select { min-height: 42px; }
.filters button { min-height: 42px; margin-top: 0; }
.filters .check label { margin: 0 0 12px; }
.filters .clear { align-self: center; margin-bottom: 6px; }

.sheetnav .arrow { padding: 6px 12px; border-radius: 999px; }
.sheetnav a.arrow:hover { background: var(--hair-2); }

/* ------------------------------ small screens ----------------------------
   Under 760px the sidebar stays where it is and becomes the icon rail --
   the owner's call, matching the reference: "it should still exist but only
   icons." An agent's phone is a real client of this system, and the rail
   costs 64px of a 390px screen. The rules live further down with the rail. */
@media (max-width: 760px) {
  .topbar { gap: 10px; }
}

/* An author display on the chip would otherwise defeat the hidden attribute,
   which is exactly how a Clear button appears with nothing to clear. */
.act[hidden], .filters .clear[hidden] { display: none; }

/* ------------------------------ sidebar card -----------------------------
   Grouped nav headings, the identity card pinned at the bottom, and the
   rail: the reference's side panel collapses to an icon strip, so ours does. */

.nav .grp {
  font-family: var(--mono); font-size: 9.5px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: #7fa89d;
  padding: 12px 12px 4px;
}
.nav .grp:first-child { padding-top: 2px; }

.side .foot {
  display: flex; align-items: center; gap: 6px;
  margin-top: auto; padding: 12px 10px 0; border-top: 1px solid var(--forest-3);
}
.side .foot .me { flex: 1; min-width: 0; text-decoration: none; border-radius: var(--r-md); padding: 6px 8px; display: block; }
.side .foot .me:hover { background: var(--forest-2); }
.side .foot .who { display: flex; align-items: center; gap: 9px; color: #dfe9e5; font-size: 12.5px; font-weight: 500; }
.side .foot .who .av {
  width: 30px; height: 30px; border-radius: 50%; background: var(--gold); color: #fff;
  display: grid; place-items: center; font-size: 11px; font-weight: 600; flex: none;
}
.side .foot .who .meta { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.side .foot .who .role {
  font-family: var(--mono); font-size: 9px; letter-spacing: .1em;
  text-transform: uppercase; color: #8fb3a9;
}
.side .foot .out {
  color: #8fb3a9; padding: 8px; border-radius: var(--r-md); display: grid; place-items: center;
}
.side .foot .out:hover { background: var(--forest-2); color: #fff; }

.railtoggle {
  background: transparent; border: 0; color: var(--muted); cursor: pointer;
  margin: 0; padding: 6px; min-height: 0; border-radius: 8px; display: grid; place-items: center;
}
.railtoggle:hover { background: var(--hair-2); color: var(--ink); transform: none; }

/* Collapsed: 64px of icons. The labels and headings go, the icons center,
   the identity card keeps only its avatar. Width animates, so the panel
   slides rather than jumps. */
.shell { transition: grid-template-columns .25s var(--ease); }
html.rail .shell { grid-template-columns: 64px 1fr; }
html.rail .side .brand .n { font-size: 13px; }
html.rail .side .brand .t,
html.rail .nav .grp,
html.rail .nav a .lbl,
html.rail .side .foot .who .meta { display: none; }
html.rail .nav a { justify-content: center; padding: 10px 0; }
html.rail .nav a:hover { transform: none; }
html.rail .side .foot { flex-direction: column; gap: 2px; padding-left: 6px; padding-right: 6px; }
html.rail .side .foot .me { padding: 6px; }

/* Under 760px the rail is not a choice, it is the layout: exactly the
   collapsed state above, whatever the hamburger says. The toggle hides,
   because a switch that can only be on is furniture. */
@media (max-width: 760px) {
  .railtoggle { display: none; }
  .shell, html.rail .shell { grid-template-columns: 64px 1fr; }
  .side .brand .n { font-size: 13px; }
  .side .brand .t,
  .nav .grp,
  .nav a .lbl,
  .side .foot .who .meta { display: none; }
  .nav a { justify-content: center; padding: 10px 0; }
  .nav a:hover { transform: none; }
  .side .foot { flex-direction: column; gap: 2px; padding-left: 6px; padding-right: 6px; }
  .side .foot .me { padding: 6px; }
}

/* -------------------------------- page fade ------------------------------
   The reference's content fades in when the side panel changes screens.
   Every navigation here is a full load, so the fade rides on load. */
@keyframes page-in {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}
.page { animation: page-in .28s var(--ease); }

/* Empty states read as a place, not an absence of markup. */
.empty {
  text-align: center; padding: 44px 20px; color: var(--muted);
  background: var(--card); border: 1px dashed var(--hair); border-radius: var(--r-lg);
}

@media (prefers-reduced-motion: reduce) {
  .shell { transition: none; }
  .page { animation: none; }
}

/* The sheet bar on a phone: the description takes the full first row and the
   two arrows share the second, instead of squeezing into one line. */
@media (max-width: 760px) {
  .sheetnav { flex-wrap: wrap; }
  .sheetnav .where { flex: 1 1 100%; order: -1; text-align: left; }
  .review-photo { padding: 8px; }
}

/* --------------------------- review, per the mockup ----------------------
   Approved from docs/mockups/sheet-review.html: the number column pairing
   table rows with sheet lines, progress dots in the sheet bar, the photo's
   tool row, the hover band, and a warn tint on a flagged row's input. */

.sheetnav .dots { display: flex; gap: 5px; justify-content: center; padding: 6px 0 0; }
.sheetnav .dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--hair); }
.sheetnav .dots i.on { background: var(--forest-3); width: 18px; border-radius: 3px; }

.review-photo .tools {
  display: flex; gap: 8px; align-items: center; justify-content: space-between;
}
.review-photo .tools .t { font-size: 11.5px; color: var(--muted); }

/* The loupe: hover the photograph and a 2.6x lens follows the pointer.
   A real sheet is dense, sectioned and photographed at arm's length; the
   lens is how small print gets read without leaving the table. */
.review-photo .frame { position: relative; border-radius: 8px; overflow: hidden; cursor: zoom-in; }
.review-photo .frame .loupe {
  position: absolute; width: 156px; height: 156px; border-radius: 50%;
  transform: translate(-50%, -50%);
  border: 2px solid var(--gold-2); box-shadow: 0 4px 18px rgba(22,32,30,.3);
  background-repeat: no-repeat; background-color: #fff;
  opacity: 0; transition: opacity .12s var(--ease);
  pointer-events: none;
}
.review-photo .frame .loupe.show { opacity: 1; }

tr.flagged input.money { border-color: var(--warn); }

/* ---------------------------- row actions --------------------------------
   Every in-table control is a real button, one uniform size, whatever
   screen it lives on. Scaled down from the primary button (same border,
   background, radius and hover treatment as button.secondary) rather than
   inventing a new visual language. */
.btn-sm {
  display: inline-flex; align-items: center; justify-content: center;
  height: 26px; min-height: 26px; padding: 0 10px; font-size: 0.85rem; line-height: 1;
  border: 1px solid var(--hair); border-radius: var(--r-md);
  background: var(--card); color: var(--forest); cursor: pointer;
  text-decoration: none; white-space: nowrap;
}
.btn-sm + .btn-sm, td.actions form + form { margin-left: 6px; }
.btn-sm:hover { border-color: var(--ink-2); background: var(--hair-2); }
td.actions { white-space: nowrap; text-align: right; width: 1%; }
td.actions form { display: inline; }
/* Rows never wrap: long data cells truncate instead. */
td.truncate { max-width: 28ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Page picker for a multi-sheet list: numbered chips under the photo tools.
   Fourteen of them have to breathe -- the owner's note -- so the row gets
   real gaps and clear air above and below before the photograph starts. */
.review-photo .pagepick { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 6px; }
.review-photo .pagepick .pg {
  min-width: 32px; height: 32px; display: grid; place-items: center;
  border: 1px solid var(--hair); border-radius: 8px; font-size: 12.5px;
  font-weight: 500; color: var(--forest-3); text-decoration: none;
  font-variant-numeric: tabular-nums;
}
.review-photo .pagepick a.pg:hover { border-color: var(--forest-3); background: var(--hair-2); }
.review-photo .pagepick .pg.on { background: var(--forest); border-color: var(--forest); color: #fff; }

/* The manager's markings over the photograph: what agents get pixelated,
   shown to the manager as outlined boxes on the untouched original. */
.review-photo .frame .redbox {
  position: absolute; border: 2px solid var(--crit);
  background: color-mix(in srgb, var(--crit) 14%, transparent);
  border-radius: 3px;
}
.review-photo .frame .redbox form { position: absolute; top: -10px; right: -10px; margin: 0; }
.review-photo .frame .redbox button {
  width: 20px; height: 20px; min-height: 0; padding: 0; margin: 0;
  border-radius: 50%; background: var(--crit); color: #fff; border: 0;
  font-size: 12px; line-height: 1; display: grid; place-items: center;
}
.review-photo .frame .redbox.ghost { pointer-events: none; border-style: dashed; }

/* ------------------------------ UX pass 1 -------------------------------- */

/* A panel around a content-sized table should not stretch past it. */
.panel.fit { width: fit-content; max-width: 100%; }

/* Pressed / disabled states for the small button family. */
.btn-sm.on  { background: var(--forest); border-color: var(--forest); color: #fff; cursor: default; }
.btn-sm.off { opacity: .45; cursor: default; pointer-events: none; }

/* The top bar's Back control sits before the title. */
.topbar .back { margin-right: 6px; }

/* Tiles that lead somewhere are the whole card: no underlined word inside. */
a.tile { color: inherit; text-decoration: none; }
.tile.go { cursor: pointer; padding-right: 28px; }
.tile.go::after {
  content: '›'; position: absolute; top: 8px; right: 12px;
  font-size: 18px; line-height: 1; color: var(--muted);
}
.tile.go:hover { border-color: var(--forest-3); box-shadow: 0 1px 6px rgba(22, 32, 30, .08); }
.tile.go:hover::after { color: var(--forest); }

/* The pager under a long table: range on the left, numbers and arrows right. */
.pager {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  flex-wrap: wrap; margin: 10px 0 4px; font-size: 12.5px; color: var(--muted);
}
.pager .pages { display: flex; align-items: center; gap: 4px; }
.pager .pages .btn-sm + .btn-sm { margin-left: 0; }
.pager .gap { padding: 0 4px; color: var(--muted); }
.pager b.btn-sm { font-weight: 600; }

/* The Delivery | Pickup pair on the estimate header: two forms, one control. */
.seg { display: inline-flex; gap: 4px; vertical-align: middle; }
.seg form { display: inline; }

/* Category chips above the material search; the pressed chip is .on. */
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 8px; }
.chips .btn-sm + .btn-sm { margin-left: 0; }

/* Picker rows: name, then category · unit in the muted ink; .hl is the keyboard cursor. */
.picker-results button .meta { color: var(--muted); font-size: 12px; }
.picker-results button.hl, .picker-results button:focus { background: var(--hair-2); outline: 0; }

/* A toolbar above a table: the summary on the left, actions on the right. */
.toolbar { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0 0 10px; }
.toolbar .summary { margin: 0; }

/* Pop-up add/edit forms. The same card look as form.card, centred. */
dialog.dlg {
  border: 1px solid var(--hair); border-radius: var(--r-lg); padding: 0;
  width: min(640px, calc(100vw - 32px)); background: var(--card); color: var(--ink);
  box-shadow: 0 12px 40px rgba(22, 32, 30, .18);
}
dialog.dlg::backdrop { background: rgba(22, 32, 30, .35); }
dialog.dlg[open]:not(:modal) { margin: 12px auto; }
.dlg header { display: flex; justify-content: space-between; align-items: center; padding: 12px 18px; border-bottom: 1px solid var(--hair-2); }
.dlg header .dlg-title { margin: 0; font-size: 15px; font-weight: 600; }
.dlg .dlg-body { padding: 14px 18px 4px; }
.dlg .dlg-body form.main { margin: 0; }
.dlg footer { display: flex; justify-content: flex-end; align-items: center; gap: 8px; padding: 12px 18px; border-top: 1px solid var(--hair-2); }
.dlg footer form.side { margin-right: auto; }
.dlg footer button, .dlg footer .btn-sm { margin-top: 0; }
.dlg .edit-only[hidden] { display: none; }

/* Client-facing documents (render_plain) keep their tables full width; the
   content-sized default is for app screens, not the quotation. */
body.plain table { width: 100%; }

/* Oversight (owner ruling 2026-09-03): an admin on a manager screen reads it
   but acts on nothing. Every POST form disappears; GET forms (filters,
   search) keep working. The server refuses such POSTs regardless. */
body.oversight form[method="post"]:not(.switch) { display: none !important; }
body.oversight .oversight-note { margin-bottom: 12px; }

/* The topbar's welcome line: who is signed in, and as what. */
.topbar .welcome { font-size: 13px; color: var(--muted); white-space: nowrap; }
.topbar .welcome b { color: var(--ink); font-weight: 600; }
.topbar .when { margin-left: 12px; }
.flash-info  { background: #eef3fa; border-color: #c9d8ee; color: #2c4a7a; }
