/* =====================================================================
   AnaciXem — THE stylesheet. One file, one place, every page.
   Link this and a page inherits the whole skin. Change it once, they all change.

   ---------------------------------------------------------------------
   HOW THE SKIN WORKS (read this before you touch a colour)

   There is ONE set of token names. There are THREE sets of values.
   A page picks its set with one attribute on <html>:

     (nothing)                  -> light. The sheet. The direction we're going.
     data-theme="light"         -> same thing, said out loud.
     data-theme="dark"          -> the night sheet. Same design, dark values.
     data-theme="terminal"      -> the OLD cyan terminal look, kept alive so the
                                   pages we haven't remodelled yet render exactly
                                   as they did before. It is scaffolding, not a
                                   design. A page drops the attribute the day it
                                   gets remodelled — that is the whole rollout plan.

   The light and dark values below are IDENTICAL to the ones in gate.html.
   gate.html is deliberately self-contained (no external stylesheet, no remote
   font — every extra request is something the page waits on before it can paint).
   If you change a light/dark value here, change it there too, or the entrance
   stops matching the rooms.

   TRAPS, learned the hard way on the gate:
     - A CSS gradient CANNOT be transitioned. Ever. It hard-cuts. Crossfade two
       stacked layers instead. That is why --body-bg exists as a token.
     - A <canvas> ignores CSS transitions completely. Any orb, chart or signature
       pad must be told the new colour in JavaScript and eased there by hand.
     - Transitions applied to only some elements read as "hard on the edges" —
       half the page fades, half snaps. Hence the html.theming rule below, which
       applies to everything, but ONLY during the 480ms flip, so focus rings and
       hovers stay instant the rest of the time.
   ===================================================================== */

/* ---------- LIGHT — the sheet (identical to gate.html) ---------- */
:root,
[data-theme="light"] {
  --void: #F4F6F8;
  --surface: #FFFFFF;
  --surface-2: #FAFBFC;
  --surface2: #FAFBFC;          /* gate spells it without the hyphen; both live here */
  --surface-alt: #FAFBFC;
  --panel-a: #FFFFFF;
  --panel-b: #FAFBFC;
  --ink: #1B2430;
  --hot: #0F1620;
  --muted: #5B6472;
  --muted-2: #8A93A3;
  --faint: #8A93A3;
  --line: #E3E6EB;
  --line-2: #E3E6EB;
  --line-strong: #D3D8E0;
  --accent: #2C5AA6;
  --accent-dim: #3E6BB5;
  --accent-soft: #EAF1FB;
  --mint: #1E8E5A;
  --go: #1E8E5A;
  --pink: #B5495C;
  --pink-soft: #FCEEEF;
  --danger: #B5495C;
  --stop: #B5495C;
  --close: #B5495C;
  --warn: #B5750F;
  --warn-bg: rgba(181,117,15,.12);
  --amber: #B5750F;
  --violet: #6B4FA8;
  --lattice: 64,86,120;
  --lattice-a: .30;
  --shadow: 0 1px 2px rgba(27,36,48,.05), 0 22px 50px -22px rgba(27,36,48,.28);
  --glow: 0 0 0 rgba(0,0,0,0);  /* light paper does not glow */
  /* the frosted pane. Three dials, because a pane that floats over a table
     of numbers has to stay READABLE first and pretty second: --pane-a is how
     opaque the tint is, --pane-blur is how hard it smears what's behind it.
     Light needs less alpha than dark — white on white already separates. */
  --pane-rgb: 255,255,255;
  --pane-a: .82;
  --pane-blur: 16px;
  --body-bg: radial-gradient(120% 100% at 50% 0,#FFFFFF 0,var(--void) 62%) fixed,var(--void);
  --scanline: transparent;
  --scan-overlay: rgba(44,90,166,.03);
  /* the lock button gate-shim.js drops on every protected page */
  --lock-bg: rgba(255,255,255,.72);
  --lock-line: rgba(44,90,166,.28);
  --lock-line-hot: rgba(181,73,92,.55);
  /* fonts ride with the skin: the sheet uses what the machine already has, so a
     remodelled page stops waiting on a font download before it can paint */
  --font: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono: ui-monospace,"Cascadia Mono","Segoe UI Mono",Consolas,monospace;
  --display: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  /* the soft/line/ink trio for the tinted message bubbles + the two extra hues
     the shell uses for its Reports and System groups. Light values are the
     literals the shell used to carry in its own :root, moved here unchanged. */
  --mint-soft: #E7F5EE;
  --mint-line: #CDE9DA;
  --mint-ink: #155C3D;
  --amber-soft: #FBF1E0;
  --amber-line: #EED9AF;
  --amber-ink: #7A4E07;
  --teal: #1B8377;
  --teal-soft: #E6F5F3;
  --violet-soft: #F1EDFB;
}

/* ---------- DARK — the night sheet (identical to gate.html) ---------- */
[data-theme="dark"] {
  --void: #0B0F16;
  --surface: #131A26;
  --surface-2: #0F1420;
  --surface2: #0F1420;
  --surface-alt: #1B2434;
  --panel-a: rgba(19,26,38,.80);
  --panel-b: rgba(11,15,22,.86);
  --ink: #E7EBF2;
  --hot: #F4F7FC;
  --muted: #96A0B0;
  --muted-2: #6A7486;
  --faint: #6A7486;
  --line: #1E2634;
  --line-2: #252F40;
  --line-strong: #2C3648;
  --accent: #4E86DC;
  --accent-dim: #6197E6;
  --accent-soft: #16233A;
  --mint: #3DBA80;
  --go: #3DBA80;
  --pink: #DB7889;
  --pink-soft: #2A161A;
  --danger: #DB7889;
  --stop: #DB7889;
  --close: #DB7889;
  --warn: #D9A63F;
  --warn-bg: rgba(217,166,63,.16);
  --amber: #D9A63F;
  --violet: #A98BE0;
  --lattice: 150,180,225;
  --lattice-a: .30;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 26px 55px -24px rgba(0,0,0,.75);
  --glow: 0 0 12px rgba(78,134,220,.35);
  --pane-rgb: 19,26,38;
  --pane-a: .88;
  --pane-blur: 20px;
  --body-bg: radial-gradient(130% 100% at 50% 0,#111925 0,var(--void) 60%) fixed,var(--void);
  --scanline: rgba(78,134,220,.03);
  --scan-overlay: rgba(78,134,220,.03);
  --lock-bg: rgba(11,15,22,.60);
  --lock-line: rgba(78,134,220,.32);
  --lock-line-hot: rgba(219,120,137,.60);
  --font: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono: ui-monospace,"Cascadia Mono","Segoe UI Mono",Consolas,monospace;
  --display: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mint-soft: #12271D;
  --mint-line: #1E4433;
  --mint-ink: #6FD3A2;
  --amber-soft: #2A2113;
  --amber-line: #4A3A1B;
  --amber-ink: #E8BE68;
  --teal: #3FB8AC;
  --teal-soft: #10272A;
  --violet-soft: #221A33;
}

/* ---------- TERMINAL — the old cyan look, on its way out ----------
   These are the exact values this file carried before 2026-07-25. Pages that
   have not been remodelled yet carry data-theme="terminal" so they render
   byte-for-byte the same as they always did. Delete a page's attribute when you
   remodel it; delete this whole block when the last page has dropped it. */
[data-theme="terminal"] {
  --void: #060A11;
  --surface: #0E1A28;
  --surface-2: #152A3D;
  --surface2: #152A3D;
  --surface-alt: #152A3D;
  --panel-a: rgba(9,17,27,.80);
  --panel-b: rgba(5,9,15,.86);
  --ink: #C3DAE8;
  --hot: #E6F4FB;
  --muted: #7093AC;
  --muted-2: #3F6580;
  --faint: #3F6580;
  --line: #1E3448;
  --line-2: #24405A;
  --line-strong: #2A4A63;
  --accent: #35D0E8;
  --accent-dim: #2E6C86;
  --accent-soft: rgba(53,208,232,.14);
  --mint: #5FE0A8;
  --go: #5FE0A8;
  --pink: #FF6FA0;
  --pink-soft: rgba(255,111,160,.14);
  --danger: #FF4D6A;
  --stop: #FF4D6A;
  --close: #FF4D6A;
  --warn: #F0A63C;
  --warn-bg: rgba(240,166,60,.14);
  --amber: #F0A63C;
  --violet: #B57BE8;
  --lattice: 53,208,232;
  --lattice-a: .22;
  --shadow: 0 0 22px rgba(53,208,232,.10);
  --glow: 0 0 12px rgba(53,208,232,.35);
  --pane-rgb: 6,10,17;
  --pane-a: .90;
  --pane-blur: 18px;
  --body-bg: radial-gradient(130% 100% at 50% 0,#0a1622 0,var(--void) 60%) fixed,var(--void);
  --scanline: rgba(53,208,232,.02);
  --scan-overlay: rgba(53,208,232,.03);
  /* exactly the literals gate-shim.js used to hardcode — pinned pages do not move */
  --lock-bg: rgba(6,10,17,.55);
  --lock-line: rgba(53,208,232,.35);
  --lock-line-hot: rgba(255,111,160,.6);
  --font: "IBM Plex Sans",system-ui,sans-serif;
  --mono: "IBM Plex Mono",monospace;
  --display: "Space Grotesk",sans-serif;
  --mint-soft: rgba(95,224,168,.14);
  --mint-line: rgba(95,224,168,.32);
  --mint-ink: #5FE0A8;
  --amber-soft: rgba(240,166,60,.14);
  --amber-line: rgba(240,166,60,.32);
  --amber-ink: #F0A63C;
  --teal: #3FE0D0;
  --teal-soft: rgba(63,224,208,.14);
  --violet-soft: rgba(181,123,232,.14);
}

/* ---------- SHAPE + MOTION — same in every skin ---------- */
:root {
  --r: 9px;
  --r-sm: 4px;
  --radius: 0px;
  --chamfer: 10px;
}

/* The flip. Class goes on <html> for 480ms while data-theme changes, then comes
   off. Everything moves together for that moment; nothing is sluggish after. */
html.theming,
html.theming *,
html.theming *::before,
html.theming *::after {
  transition: background-color .42s ease, border-color .42s ease, color .42s ease,
              box-shadow .42s ease, fill .42s ease, stroke .42s ease, opacity .42s ease !important;
}
@media (prefers-reduced-motion: reduce) {
  html.theming, html.theming *, html.theming *::before, html.theming *::after {
    transition: none !important;
  }
}
body,
html {
  margin: 0;
  padding: 0
}
.field input,
.field select,
.field textarea,
.linecard,
.linecard *,
.regbox {
  box-sizing: border-box
}
body {
  background: var(--body-bg);
  color: var(--ink);
  font-family: var(--font)
}
.app {
  min-height: 100vh;
  display: flex;
  flex-direction: column
}
.appbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px;
  height: 46px;
  background: linear-gradient(180deg,var(--surface-2),var(--surface));
  border-bottom: 1px solid var(--line-strong)
}
.app-name {
  font-family: var(--display);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: .04em;
  color: var(--hot)
}
.app-crumb {
  color: var(--muted);
  font-weight: 500;
  font-family: var(--font)
}
.spacer {
  flex: 1
}
.env {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted)
}
.env .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--mint);
  box-shadow: 0 0 7px var(--mint)
}
.menubar {
  position: relative;
  display: flex;
  gap: 2px;
  padding: 3px 10px;
  background: var(--surface);
  border-bottom: 1px solid var(--line)
}
.menu-btn {
  font-family: var(--font);
  font-size: 12.5px;
  color: var(--muted);
  background: 0 0;
  border: 0;
  padding: 5px 11px;
  border-radius: var(--r-sm);
  cursor: pointer
}
.menu-btn.open,
.menu-btn:hover {
  background: var(--surface-2);
  color: var(--accent)
}
.menu-pop {
  display: none;
  position: absolute;
  top: 34px;
  z-index: 60;
  min-width: 170px;
  padding: 5px;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  box-shadow: 0 12px 34px rgba(0,0,0,.5)
}
.menu-pop.show {
  display: block
}
.menu-item {
  padding: 8px 12px;
  font-size: 13px;
  color: var(--ink);
  border-radius: 3px;
  cursor: pointer
}
.menu-item:hover {
  background: var(--accent-soft);
  color: var(--accent)
}
.app-body {
  flex: 1;
  padding: 16px
}
.card {
  background: linear-gradient(180deg,var(--panel-a),var(--panel-b));
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  padding: 15px 16px;
  box-shadow: var(--shadow)
}
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--line)
}
.card-head h2 {
  margin: 0;
  font-family: var(--display);
  font-size: 14px;
  font-weight: 600;
  color: var(--hot);
  letter-spacing: .02em
}
.hint {
  font-size: 12px;
  color: var(--muted-2);
  font-family: var(--font)
}
.count-badge {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent);
  border: 1px solid var(--accent-dim);
  background: var(--accent-soft);
  border-radius: 11px;
  padding: 2px 9px
}
.seclabel {
  font-family: var(--display);
  font-size: 10.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 8px
}
.seclabel.mt {
  margin-top: 16px
}
.seclabel .lite {
  color: var(--muted-2);
  letter-spacing: .02em;
  text-transform: none;
  font-family: var(--font);
  font-size: 11px
}
.field {
  margin-bottom: 10px
}
.field label {
  display: block;
  font-size: 10px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: 5px
}
.field input,
input.big {
  width: 100%;
  height: 36px;
  padding: 0 11px;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-bottom: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  font-family: var(--mono);
  font-size: 15px
}
.field input:focus {
  outline: 0;
  border-bottom: 2px solid var(--accent)
}
.field input::placeholder {
  font-family: var(--font);
  color: var(--muted-2)
}
.btn {
  font-family: var(--font);
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  padding: 9px 15px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color .15s,color .15s,box-shadow .15s,background .15s
}
.btn:hover {
  border-color: var(--accent);
  color: var(--hot)
}
.btn-accent {
  background: var(--accent-soft);
  border-color: var(--accent-dim);
  color: var(--accent)
}
.btn-accent:hover {
  box-shadow: var(--glow);
  border-color: var(--accent);
  color: var(--hot)
}
.btn:disabled {
  opacity: .45;
  cursor: not-allowed;
  box-shadow: none;
  border-color: var(--line-strong);
  color: var(--muted)
}
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 40px 16px;
  color: var(--muted-2);
  text-align: center
}
.empty svg {
  width: 42px;
  height: 42px;
  opacity: .5
}
.empty .big {
  font-size: 14px;
  color: var(--muted);
  font-family: var(--display)
}
.statusbar {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 16px;
  font-size: 12px;
  color: var(--muted);
  background: var(--surface);
  border-top: 1px solid var(--line-strong)
}
.sb-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--mint);
  box-shadow: 0 0 7px var(--mint)
}
.sb-spacer {
  flex: 1
}
.modal-scrim {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(3,6,11,.72);
  align-items: center;
  justify-content: center;
  padding: 4vh 4vw
}
.modal-scrim.show {
  display: flex
}
.modal {
  width: min(560px,94vw);
  max-height: 88vh;
  overflow: auto;
  background: linear-gradient(180deg,var(--surface-2),var(--surface));
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  box-shadow: 0 24px 60px rgba(0,0,0,.6)
}
.modal-head {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 600;
  color: var(--hot);
  padding: 16px 18px;
  border-bottom: 1px solid var(--line)
}
.modal-body {
  padding: 16px 18px;
  line-height: 1.55;
  color: var(--ink);
  font-size: 13.5px
}
.modal-foot {
  display: flex;
  justify-content: flex-end;
  padding: 12px 18px;
  border-top: 1px solid var(--line)
}
.li-row.grp-hi {
  background: var(--accent-soft)
}
.li-label .li-tag.buy {
  background: rgba(240,166,60,.16);
  background: color-mix(in srgb, var(--amber) 16%, transparent);
  border-color: var(--amber);
  color: var(--amber)
}
.li-row .x:hover {
  background: rgba(255,77,106,.16);
  background: color-mix(in srgb, var(--stop) 16%, transparent)
}
.addli:hover {
  background: var(--surface-2)
}
.guide-note {
  background: var(--accent-soft)
}
.consol-card {
  background: var(--accent-soft)
}
.consol-card.done {
  background: rgba(95,224,168,.14);
  background: color-mix(in srgb, var(--go) 14%, transparent)
}
.consol-card button {
  color: var(--void)
}
#ticketActions.loud .btn:hover {
  background: rgba(255,77,106,.16);
  background: color-mix(in srgb, var(--stop) 16%, transparent)
}
.li-inputs .li-field {
  flex: 0 0 auto
}
.li-inputs .li-cases,
.li-inputs .li-per {
  width: 92px
}
.lines {
  display: flex;
  flex-direction: column;
  gap: 10px
}
.linecard {
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: var(--surface-alt);
  padding: 10px;
  position: relative
}
.linecard .lc-grid {
  display: grid;
  grid-template-columns: minmax(0,1fr) 104px;
  gap: 8px
}
.linecard .f {
  display: flex;
  flex-direction: column;
  min-width: 0
}
.linecard .f.lc-full {
  grid-column: 1/-1;
  padding-right: 30px
}
.linecard .f label {
  font-size: 10.5px;
  color: var(--muted-2);
  text-transform: uppercase;
  letter-spacing: .4px;
  margin-bottom: 3px
}
.linecard input,
.linecard select {
  height: 30px;
  padding: 0 8px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  font-family: var(--font);
  font-size: 13px;
  color: var(--ink);
  width: 100%;
  min-width: 0
}
.linecard input:focus,
.linecard select:focus {
  outline: 0;
  border-bottom: 2px solid var(--accent)
}
.linecard .f.block input,
.linecard .f.qty input {
  background: rgba(240,166,60,.14);
  background: color-mix(in srgb, var(--amber) 14%, transparent);
  color: var(--hot);
  font-weight: 600
}
.linecard .rm {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 24px;
  height: 24px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--muted-2);
  cursor: pointer;
  font-size: 14px;
  line-height: 1
}
.linecard .rm:hover {
  background: rgba(255,77,106,.16);
  background: color-mix(in srgb, var(--stop) 16%, transparent);
  border-color: var(--close);
  color: var(--close)
}
.addline {
  width: 100%;
  height: 36px;
  border: 1px dashed var(--line-2);
  border-radius: var(--r-sm);
  background: var(--surface-alt);
  color: var(--accent);
  font-family: var(--font);
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  box-sizing: border-box
}
.addline:hover {
  background: var(--accent-soft);
  border-color: var(--accent)
}
.framed .appbar,
.framed .menubar {
  display: none!important
}
.zoomctl {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
  margin-right: 10px
}
.zoomctl button {
  min-width: 26px;
  height: 22px;
  padding: 0 7px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: 0 0;
  color: var(--muted);
  font-family: var(--font);
  font-size: 12px;
  line-height: 1;
  cursor: pointer
}
.zoomctl button.on,
.zoomctl button:hover {
  border-color: var(--accent);
  color: var(--accent)
}
.zoomctl .zlbl {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted-2);
  min-width: 36px;
  text-align: right
}
body.scan::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: .35;
  background: repeating-linear-gradient(0deg,var(--scan-overlay) 0 1px,transparent 1px 3px)
}
.eyebrow {
  font-family: var(--display);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent)
}
.mono,
code,
kbd {
  font-family: var(--mono)
}
.muted {
  color: var(--muted)
}
.faint {
  color: var(--faint)
}
.go {
  color: var(--go)
}
.stop {
  color: var(--stop)
}
.glow {
  text-shadow: var(--glow)
}
.card-title {
  font-family: var(--display);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 12px
}
.btn-ghost {
  background: 0 0
}
.btn-danger:hover {
  border-color: var(--danger);
  color: var(--danger)
}
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 2px 9px;
  border-radius: 11px;
  border: 1px solid var(--line-strong);
  color: var(--muted);
  background: var(--surface)
}
.badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 7px currentColor
}
.badge.accent {
  color: var(--accent);
  border-color: var(--accent-dim)
}
.badge.go {
  color: var(--go);
  border-color: rgba(95,224,168,.5);
  border-color: color-mix(in srgb, var(--go) 50%, transparent)
}
.badge.stop {
  color: var(--stop);
  border-color: rgba(255,77,106,.5);
  border-color: color-mix(in srgb, var(--stop) 50%, transparent)
}
.badge.amber {
  color: var(--amber);
  border-color: rgba(240,166,60,.5);
  border-color: color-mix(in srgb, var(--amber) 50%, transparent)
}
.badge.violet {
  color: var(--violet);
  border-color: rgba(181,123,232,.5);
  border-color: color-mix(in srgb, var(--violet) 50%, transparent)
}
.hr {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 16px 0
}
.stack {
  display: flex;
  flex-direction: column;
  gap: 12px
}
.row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: flex-start
}
.wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px
}

/* ===== Shared tool shell (drop zone / paste / loading / board / topbar / tiles) =====
   Pulled out of orders.html + inventory.html 2026-07-24 — both had byte-identical copies
   of this block, which is exactly the "duplicated rules fighting each other" the project
   rule warns about. One copy here now; any report-reading tool (orders/inventory/staging)
   uses these classes instead of re-pasting them. */
body.tool-shell {
  padding: 26px 22px 60px;
  background: var(--void);
  background-image: repeating-linear-gradient(0deg,var(--scanline) 0 1px,transparent 1px 3px)
}
.head .eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent)
}
.head h1 {
  font-family: var(--display);
  font-size: 25px;
  font-weight: 700;
  color: var(--hot);
  margin: 5px 0 5px;
  letter-spacing: -.3px
}
.head .sub b {
  color: var(--mint)
}
.drop {
  margin-top: 22px;
  border: 1.5px dashed var(--line-strong);
  border-radius: 14px;
  background: var(--panel-a);
  padding: 46px 24px;
  text-align: center;
  cursor: pointer;
  transition: border-color .18s,background .18s
}
.drop.over, .drop:hover {
  border-color: var(--accent);
  background: var(--accent-soft)
}
.drop .big {
  font-family: var(--display);
  font-size: 17px;
  color: var(--hot)
}
.drop .small {
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 6px
}
.drop .ic {
  font-size: 30px;
  opacity: .8
}
#file {
  display: none
}
.loading {
  display: none;
  margin-top: 22px;
  align-items: center;
  gap: 12px;
  color: var(--muted);
  font-size: 13px;
  font-family: var(--mono)
}
.loading.show {
  display: flex
}
.spin {
  width: 15px;
  height: 15px;
  border: 2px solid var(--line-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: sp .7s linear infinite
}
@keyframes sp {
  to {
    transform: rotate(360deg)
  }
}
.board {
  display: none
}
.board.show {
  display: block
}
.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 18px
}
.topbar .fn {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--accent)
}
.topbar .spacer {
  flex: 1
}
.tile {
  background: var(--panel-a);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 13px 15px
}
.tile .k {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted-2)
}
.tile .v {
  font-family: var(--display);
  font-size: 22px;
  font-weight: 700;
  color: var(--hot);
  margin-top: 3px
}
.tile .v.warn {
  color: var(--amber)
}
.tile .v.stop {
  color: var(--danger)
}
.tile .v.ok {
  color: var(--mint)
}
.tile .u {
  font-size: 11px;
  color: var(--muted)
}
.note {
  margin-top: 24px;
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.6;
  border-left: 2px solid var(--accent-dim);
  padding: 4px 0 4px 14px
}
.note b {
  color: var(--ink)
}
.note .mint {
  color: var(--mint)
}
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit,minmax(145px,1fr));
  gap: 12px;
  margin: 18px 0
}
.pasterow {
  margin-top: 11px;
  text-align: center
}
.linkbtn {
  background: 0 0;
  border: none;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  cursor: pointer;
  text-decoration: underline
}
.pastebox {
  margin-top: 12px
}
.pastebox textarea {
  width: 100%;
  min-height: 120px;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  font-family: var(--mono);
  font-size: 11.5px;
  padding: 10px;
  resize: vertical;
  white-space: pre;
  overflow: auto
}
.pasteact {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 8px;
  flex-wrap: wrap
}
.pastenote {
  font-size: 11.5px;
  color: var(--amber)
}
.empty2 {
  color: var(--muted-2);
  font-size: 13px;
  padding: 30px;
  text-align: center
}
/* ===== The theme switch — the eclipse =====================================
   A sun that a shadow slides across into a crescent, rays retracting as it goes.
   ONE object moving. Nothing is swapped for a different picture — that is the
   whole reason it doesn't read as static the way a sun/moon icon does.
   Markup + wiring: lib/theme.js (AXTheme.mount). gate.html carries its own copy
   because it is deliberately standalone; keep the two identical. */
.themetoggle {
  width: 28px;
  height: 28px;
  border-radius: 99px;
  cursor: pointer;
  flex: none;
  padding: 0;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color .2s, color .2s, box-shadow .2s
}
.themetoggle:hover {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft)
}
.themetoggle svg {
  width: 16px;
  height: 16px;
  overflow: visible
}
.themetoggle .body {
  fill: currentColor
}
.themetoggle .bite {
  fill: #000;
  transition: transform .55s cubic-bezier(.5,0,.2,1)
}
[data-theme="dark"] .themetoggle .bite,
[data-theme="terminal"] .themetoggle .bite {
  transform: translate(-7.5px,5px)
}
.themetoggle .rays {
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  fill: none;
  opacity: 1;
  transform-origin: 12px 12px;
  transition: opacity .4s, transform .55s cubic-bezier(.5,0,.2,1)
}
[data-theme="dark"] .themetoggle .rays,
[data-theme="terminal"] .themetoggle .rays {
  opacity: 0;
  transform: scale(.6) rotate(45deg)
}
@media print {
  .themetoggle { display: none !important }
}

/* ===== The corner — where the switch and the lock live ====================
   Every page's chrome collects in one place instead of each control picking
   its own fixed corner and landing on top of the next one. Put data-ax-lock
   on this element and gate-shim docks the lock button into the row in normal
   flow, so the two never overlap and no page needs a nudge of its own.

   A page that already has its own top-right cluster (the style guide's "‹ home"
   row) just marks that cluster instead. One rule, two ways in. */
.ax-corner {
  position: fixed;
  top: 14px;
  right: 16px;
  z-index: 2147482000;
  display: flex;
  align-items: center;
  gap: 10px
}
@media print {
  .ax-corner { display: none !important }
}

/* ===== Order memory — the recall bar =====================================
   The strip a tool shows when the number just typed is one it has seen
   before: what it remembers, when it remembered it, and two plain choices.

   It lives HERE and not inside the placard page because receiving and the
   BOL want the same strip the moment they learn to remember an order, and a
   second copy of these rules in a second page is the exact bug this project
   has already paid for once. Tokens only — no literal colours — so it wears
   whichever skin the page is in without a second palette being written down.

   It is deliberately loud-ish (accent tint, not grey): a remembered order is
   news, and news the clerk misses is a ticket he re-pastes for nothing. */
.axrecall {
  margin: 8px 0 2px;
  padding: 9px 11px;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-radius: var(--r-sm);
  font-size: 12px;
  line-height: 1.5
}
.axrecall[hidden] { display: none }
.axrecall .what { color: var(--ink); font-weight: 600 }
.axrecall .what b { font-family: var(--mono) }
.axrecall .when { color: var(--muted); margin-top: 1px }
.axrecall .where { color: var(--muted-2); font-size: 11px; margin-top: 3px }
.axrecall .acts { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap }
.axrecall .acts button {
  height: 28px;
  padding: 0 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  font-family: var(--font);
  font-weight: 600;
  font-size: 12px;
  cursor: pointer
}
.axrecall .acts button.ghost {
  background: 0 0;
  color: var(--muted-2);
  border-color: var(--line-2)
}
.axrecall .acts button:hover { filter: brightness(1.05) }

/* the drift line: today's read of the ticket disagrees with what was printed
   last time. NEVER silently reconciled — the two numbers are shown side by
   side and the human picks. Amber, because it is a question, not a failure. */
.axdrift {
  margin-top: 9px;
  padding: 9px 11px;
  background: var(--amber-soft);
  border: 1px solid var(--amber-line);
  border-radius: var(--r-sm);
  color: var(--amber-ink);
  font-size: 12px;
  line-height: 1.5
}
.axdrift b { font-family: var(--mono) }

/* the drawer list — one row per remembered order */
.axmemlist { display: flex; flex-direction: column; gap: 8px }
.axmemrow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 11px;
  background: var(--surface-alt);
  border: 1px solid var(--line);
  border-radius: var(--r-sm)
}
.axmemrow .num { font-family: var(--mono); font-weight: 700; color: var(--ink); font-size: 13px }
.axmemrow .sub { color: var(--muted-2); font-size: 11.5px; margin-top: 1px }
.axmemrow .grow { flex: 1; min-width: 0 }
.axmemrow button {
  flex: 0 0 auto;
  height: 28px;
  padding: 0 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  font-family: var(--font);
  font-weight: 600;
  font-size: 12px;
  cursor: pointer
}
.axmemrow button.ghost { background: 0 0; color: var(--muted-2); border-color: var(--line-2) }
.axmemempty { color: var(--muted-2); font-size: 12.5px; line-height: 1.6 }

/* =====================================================================
   THE REPORT TABLE  (.strip / .rt)
   Shared component. Any page that lays out rows she read off a file —
   inventory tonight, SOI and receiving later — uses these. It lives here
   ONCE. Do not paste any of it back into a tool page.

   The idea: eight tiles was eight places for the eye to land. One line
   of numbers, then one table whose columns are always in the same order,
   is one place. Columns COLLAPSE when a file doesn't bring them; they
   never reshuffle, so the third column is the third column every night.
   ===================================================================== */

/* the readout strip — one line, not eight boxes. Number first, because
   the number is what you came for; the word after it small, because you
   only read the word the first week. */
.strip{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 20px;margin:16px 0 12px;
  padding:9px 13px;border:1px solid var(--line);border-radius:10px;background:var(--panel-a)}
.strip .s{display:flex;align-items:baseline;gap:5px;white-space:nowrap}
.strip .n{font-family:var(--display);font-size:15px;font-weight:700;color:var(--hot);letter-spacing:-.01em}
.strip .n.warn{color:var(--amber)}
.strip .n.stop{color:var(--danger)}
.strip .n.ok{color:var(--mint)}
.strip .w{font-size:11.5px;color:var(--muted)}
.strip .sep{width:1px;align-self:stretch;background:var(--line);margin:0 -6px}
.strip .s.act{cursor:pointer;border-bottom:1px dashed var(--amber);padding-bottom:1px}
.strip .s.act:hover .n{filter:brightness(1.15)}

/* mode buttons + the one-checkbox toggles that sit next to them */
.seg{display:inline-flex;border:1px solid var(--line-2);border-radius:var(--r-sm);overflow:hidden}
.seg button{background:var(--surface);border:0;border-right:1px solid var(--line-2);color:var(--muted);
  font-family:var(--font);font-size:12.5px;padding:6px 11px;cursor:pointer}
.seg button:last-child{border-right:0}
.seg button.on{background:var(--accent-soft);color:var(--accent);font-weight:600}
.tog{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--muted);cursor:pointer;
  border:1px solid var(--line-2);border-radius:var(--r-sm);padding:5px 10px;background:var(--surface)}
.tog.on{border-color:var(--amber);color:var(--amber);background:var(--amber-soft)}
.tog input{display:none}

.rtwrap{border:1px solid var(--line);border-radius:12px;background:var(--panel-b);
  overflow:auto;max-height:66vh;box-shadow:var(--shadow)}
table.rt{border-collapse:separate;border-spacing:0;width:100%;font-size:12px}

/* two header rows: the QUESTION the band answers, then the field names.
   The bands are what let the eye jump — you learn "how much lives in the
   third band" once, and after that you stop reading headers. */
table.rt thead th{position:sticky;background:var(--surface-2);white-space:nowrap;
  border-bottom:1px solid var(--line);text-align:left}
table.rt thead tr.bands th{top:0;z-index:5;height:23px;padding:0 10px;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted-2);border-bottom:1px solid var(--line-2)}
table.rt thead tr.names th{top:23px;z-index:5;height:27px;padding:0 10px;
  font-family:var(--mono);font-size:10px;letter-spacing:.05em;text-transform:uppercase;color:var(--muted)}
table.rt thead th.band-b{border-left:1px solid var(--line-2)}
table.rt th.stick,table.rt td.stick{position:sticky;left:0;z-index:3;background:var(--surface-2)}
table.rt th.stick2,table.rt td.stick2{position:sticky;left:34px;z-index:3;background:var(--surface-2)}
table.rt thead th.stick,table.rt thead th.stick2{z-index:6}
table.rt tbody td{padding:5px 10px;border-bottom:1px solid var(--line);color:var(--ink);white-space:nowrap}
table.rt tbody td.num{font-family:var(--mono);text-align:right}
table.rt tbody td.mono{font-family:var(--mono)}
table.rt tbody td.band-b{border-left:1px solid var(--line-2)}
table.rt tbody tr:hover td{background:var(--surface)}
table.rt tbody tr:hover td.stick,table.rt tbody tr:hover td.stick2{background:var(--surface)}

/* the age lane */
table.rt td.age.aged{color:var(--amber);font-weight:600}
table.rt td.age.old{color:var(--danger);font-weight:700}
table.rt tr.aged td{background:color-mix(in srgb,var(--amber) 6%,transparent)}
table.rt tr.aged td.stick,table.rt tr.aged td.stick2{background:color-mix(in srgb,var(--amber) 6%,var(--surface-2))}

/* the vault lane — the one column the eye scans for trouble.
   ● agrees · ▲ the count differs · ◆ the vault never saw this tag
   ○ the vault still thinks it's here · · she couldn't check */
.chk{display:inline-block;width:15px;text-align:center;font-family:var(--mono);font-size:12px;line-height:1}
.chk.ok{color:var(--mint)}
.chk.diff{color:var(--amber)}
.chk.new{color:var(--danger)}
.chk.ghost{color:var(--violet)}
.chk.dunno{color:var(--muted-2)}
table.rt tr.diff td{background:color-mix(in srgb,var(--amber) 12%,transparent)}
table.rt tr.diff td.stick,table.rt tr.diff td.stick2{background:color-mix(in srgb,var(--amber) 12%,var(--surface-2))}
table.rt tr.new td{background:color-mix(in srgb,var(--danger) 10%,transparent)}
table.rt tr.new td.stick,table.rt tr.new td.stick2{background:color-mix(in srgb,var(--danger) 10%,var(--surface-2))}
table.rt tr.ghost td{background:color-mix(in srgb,var(--violet) 8%,transparent);color:var(--muted);font-style:italic}
table.rt tr.ghost td.stick,table.rt tr.ghost td.stick2{background:color-mix(in srgb,var(--violet) 8%,var(--surface-2))}
.vsay{font-family:var(--mono);font-size:10.5px;color:var(--amber)}

/* subtotal bands — the group lives INSIDE the one table, so the columns
   never shift under you when you change what you group by. */
table.rt tr.gband td{background:var(--surface);border-top:1px solid var(--line-strong);
  border-bottom:1px solid var(--line-strong);padding:7px 10px}
table.rt tr.gband td.stick,table.rt tr.gband td.stick2{background:var(--surface)}
table.rt .gname{font-family:var(--display);font-weight:700;font-size:13px;color:var(--hot)}
table.rt .gstats{margin-left:14px;font-family:var(--mono);font-size:11px;color:var(--muted)}
table.rt .gstats b{color:var(--ink)}
table.rt .gstats .amber{color:var(--amber)}
table.rt .gstats span{margin-right:15px}

/* she says out loud which columns the file didn't bring. Never a silent cap. */
.hidden-note{font-size:11.5px;color:var(--muted-2);font-family:var(--mono);margin:9px 2px 0}
.hidden-note b{color:var(--muted);font-weight:400;border-bottom:1px dotted var(--line-strong)}
.legend{display:flex;gap:18px;flex-wrap:wrap;font-size:11.5px;color:var(--muted);margin:11px 2px 0}
.legend span{display:inline-flex;align-items:center;gap:6px}

/* the empty state a report page shows before anything is loaded */
.waiting{margin-top:26px;border:1px solid var(--line);border-radius:14px;background:var(--panel-a);
  padding:44px 26px;text-align:center;box-shadow:var(--shadow)}
.waiting .ic{font-size:26px;opacity:.5}
.waiting .big{font-family:var(--display);font-size:17px;color:var(--hot);margin-top:8px}
.waiting .small{font-size:12.5px;color:var(--muted);margin-top:7px;line-height:1.6}
.waiting .small b{color:var(--accent)}

/* =====================================================================
   HER ANSWERS  (.axans)

   lib/ax-ask.js returns HTML for the caller to drop in a bubble. Those
   answers get the SAME look on the console chat, on her.html, and on
   anything built later — which is exactly why they live here and not in
   a page's private <style>.

   EVERY rule is scoped under .axans on purpose. Her markup uses short
   names — .big, .sub, .f, .src — and this sheet already spends .big,
   .sub and .f on other components. Unscoped, they'd fight, and the loser
   would be whichever one loaded second. Scoping is the fix, never
   specificity games.
   ===================================================================== */
.axans{line-height:1.55}
.axans b{color:var(--accent);font-weight:600}

/* a table's or endpoint's shape: name on the left, type on the right */
.axans .fieldlist{display:grid;grid-template-columns:auto 1fr;gap:2px 10px;margin:7px 0 2px;font-size:12px}
.axans .fieldlist .f{font-family:var(--mono,ui-monospace,monospace);color:var(--ink);white-space:nowrap}
/* the note WRAPS. nowrap looked tidy on "uuid" and then ran a column like
   "text · unique — no two rows share it · required" straight off the right
   edge of the bubble, where there is no way to scroll to it. A field she
   can't finish saying is worse than a ragged line. */
.axans .fieldlist .t{color:var(--muted);text-align:right;min-width:0;overflow-wrap:anywhere}

/* where she got it — always the last line, always quiet */
.axans .src{margin-top:8px;padding-top:6px;border-top:1px solid var(--line);font-size:11px;color:var(--faint)}

/* a verdict: the number said loud, the qualifiers said small under it */
.axans .big{display:block;font-family:var(--display);font-size:19px;line-height:1.2;color:var(--hot)}
.axans .sub{margin-top:3px;font-size:11.5px;color:var(--muted)}

/* =====================================================================
   HER PANEL  (.axpane)  — the squared frosted chat.

   The fan is dead; Jose picked the square. This is the real one, so it
   lives here and not inside a tool page: inventory gets it first, home
   and staging get the same object for free, and there is exactly one
   place to change how she looks.

   It is FIXED and it FLOATS because the page under it is the answer.
   You ask, the table behind her changes, and you watch it change — a
   panel that pushed the table sideways would hide the very thing you
   asked about.

   Named .axpane and not .panel on purpose: train.html already owns a
   .panel class, and two rules with the same name fighting each other in
   one stylesheet is how the last round of "few pixels off" bugs started.

   EVERY class in here is ax-prefixed, including the little ones inside
   the pane. That is not tidiness, it is a bug I already shipped once:
   the attachment tile was class="axf inv", inventory.html's page wrapper
   is .inv{max-width:1180px;margin:0 auto}, and the tile inherited the
   auto margins and floated 140px away from its neighbour. A pane that
   drops onto ANY page cannot use a plain word as a class name — .field,
   .go, .box and .inv are all already spoken for somewhere.
   ===================================================================== */
.axpane{position:fixed;right:18px;bottom:18px;width:376px;height:min(524px,calc(100vh - 36px));
  z-index:60;
  background:rgba(var(--pane-rgb),var(--pane-a));
  -webkit-backdrop-filter:blur(var(--pane-blur)) saturate(150%);
          backdrop-filter:blur(var(--pane-blur)) saturate(150%);
  border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow);
  display:flex;flex-direction:column;overflow:hidden;
  transition:background .25s,opacity .18s,transform .18s}

/* A browser that can't frost gets the solid surface. A see-through pane
   with nothing behind it is unreadable, not degraded — and the work PC
   is the machine most likely to be the one that can't. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .axpane{background:var(--surface)}
}
/* an escape hatch that survives the deploy: ?solid on the URL, or the
   toggle, kills the frost without a code change */
body.solid .axpane{background:var(--surface)!important;
  backdrop-filter:none;-webkit-backdrop-filter:none}

/* closed: she folds into her own corner rather than vanishing, so the
   way back is where she was */
.axpane.axmin{height:auto;width:auto}
.axpane.axmin .axpane-thread,
.axpane.axmin .axatt,
.axpane.axmin .axinp{display:none}
.axpane.axmin .axpane-head{border-bottom:0;cursor:pointer}
/* she said something while you had her folded away. She does NOT throw
   herself open over the page you are reading — the corner just lights up
   and waits. Ring on the dot rather than a number, because the count of
   unread lines is not information you can act on; that she spoke is. */
.axpane.axmin.axnew .axpane-head .axdot{background:var(--amber);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--amber) 26%,transparent);
  animation:axpulse 1.6s ease-in-out infinite}
.axpane.axmin.axnew .axpane-head .axnm::after{content:"·";color:var(--amber);
  margin-left:5px;font-weight:800}

.axpane-head{display:flex;align-items:center;gap:8px;padding:12px 14px;
  border-bottom:1px solid var(--line);flex:0 0 auto}
.axpane-head .axdot{width:8px;height:8px;border-radius:50%;background:var(--mint);
  flex:0 0 auto;transition:background .2s}
/* she is thinking / reading a file — the dot is the only status light
   there is, because a status LINE would be one more thing to read */
.axpane.axbusy .axpane-head .axdot{background:var(--amber);animation:axpulse 1s ease-in-out infinite}
@keyframes axpulse{0%,100%{opacity:1}50%{opacity:.25}}
.axpane-head .axnm{font-family:var(--display);font-size:13.5px;font-weight:650;color:var(--hot)}
.axpane-head .axsp{flex:1}
.axpane-head .axclose{color:var(--faint);font-size:15px;line-height:1;cursor:pointer;
  background:none;border:0;padding:0 2px;font-family:var(--font)}
.axpane-head .axclose:hover{color:var(--ink)}

.axpane-thread{flex:1;overflow-y:auto;overflow-x:hidden;padding:14px;
  display:flex;flex-direction:column;gap:11px}
.axmsg{max-width:82%;padding:9px 12px;border-radius:12px;font-size:12.5px;line-height:1.55;
  animation:axin .18s ease-out}
@keyframes axin{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.axmsg.axme{align-self:flex-end;background:var(--accent);color:#fff;border-bottom-right-radius:4px}
.axmsg.axher{align-self:flex-start;background:var(--mint-soft);border:1px solid var(--mint-line);
  color:var(--ink);border-bottom-left-radius:4px}
.axmsg.axher b{color:var(--mint-ink);font-weight:650}
/* three tints, and only three. Her default bubble is mint because most of
   what she says is an answer. Amber is "look at this before you print it",
   grey is "I didn't catch that" — a miss must not wear the same colour as
   a confirmed number. .axsrc borrows the bubble's own border colour so the
   receipt line never fights the tint it is sitting inside. */
.axmsg.axher.axwarn{background:var(--amber-soft);border-color:var(--amber-line)}
.axmsg.axher.axwarn b{color:var(--amber-ink)}
.axmsg.axher.axwarn .axsrc{border-top-color:var(--amber-line)}
.axmsg.axher.axmute{background:var(--surface2);border-color:var(--line);color:var(--muted)}
.axmsg.axher.axmute b{color:var(--ink)}
.axmsg.axher.axmute .axsrc{border-top-color:var(--line)}
/* where she got it. Every number she says should be traceable to a file
   you handed her — this line is that receipt. */
.axmsg .axsrc{display:block;margin-top:7px;padding-top:6px;border-top:1px solid var(--mint-line);
  color:var(--muted);font-size:11px;line-height:1.4}

/* The one question, answered by clicking — typing "room 2" to answer
   "which room?" is doing her work twice. (This replaced an earlier
   .askstrip strip that lived outside the panel; that block is gone.) */
.axmsg .axopts{display:flex;flex-wrap:wrap;gap:6px;margin-top:9px}
.axmsg .axopt{font-family:var(--mono);font-size:11.5px;line-height:1;padding:5px 9px;
  border:1px solid var(--mint-line);border-radius:var(--r-sm);
  background:var(--surface);color:var(--ink);cursor:pointer;
  transition:border-color .15s,color .15s}
.axmsg .axopt:hover{border-color:var(--mint);color:var(--mint-ink)}
.axmsg .axopt.axall{border-color:transparent;background:transparent;color:var(--muted);
  font-family:var(--font)}
.axmsg .axopt.axall:hover{color:var(--ink)}

/* =====================================================================
   THE ATTACHMENT ROW — icon only.

   It sits on a thin strip directly above the input, because that is where
   the thing you are about to ask about belongs: between the thread and
   the question. It has no title, and it disappears when nothing is held.

   Icon only was the choice. The name and the count are real information,
   but they are information you want ONCE — so they live in the hover
   tooltip and cost nothing the rest of the time.
   ===================================================================== */
.axatt{flex:0 0 auto;display:flex;align-items:center;gap:7px;padding:9px 14px 0}
.axf{position:relative;display:flex;align-items:center;justify-content:center;
  width:28px;height:28px;padding:0;
  border:1px solid var(--line-strong);border-radius:8px;background:var(--surface-2);
  color:var(--muted);font-size:11.5px;cursor:default;
  transition:border-color .15s,color .15s}
.axf:hover{border-color:var(--accent);color:var(--ink)}
.axf svg{width:14px;height:14px;flex:0 0 auto;display:block}
/* amber grid = where things live. green box = what is in them. */
.axf.axk-rooms{color:var(--warn)} .axf.axk-rooms:hover{color:var(--warn);border-color:var(--warn)}
.axf.axk-inv{color:var(--mint)}   .axf.axk-inv:hover{color:var(--mint);border-color:var(--mint)}
.axf.axk-add{border-style:dashed;color:var(--faint);cursor:pointer}
.axf.axk-add:hover{border-color:var(--accent);color:var(--accent)}

/* the × exists only while the pointer is on the tile. Two files sitting
   there with two permanent little crosses is exactly the noise he asked
   me to take out — the cross is for the moment you want it gone. */
.axf .axkill{position:absolute;top:-6px;right:-6px;width:15px;height:15px;border-radius:50%;
  background:var(--ink);color:var(--surface);font-size:10px;line-height:15px;text-align:center;
  opacity:0;transition:opacity .15s;cursor:pointer;border:0;padding:0;font-family:var(--font)}
.axf:hover .axkill{opacity:1}

/* the name grows to the RIGHT from the tile's left edge, not centred on
   it — the pane clips its own overflow, and a centred tooltip on the
   first tile gets its front half cut off by the pane wall. */
.axf .axtip{position:absolute;bottom:calc(100% + 7px);left:-1px;
  white-space:nowrap;padding:5px 9px;border-radius:7px;background:var(--hot);color:var(--void);
  font-size:11px;opacity:0;transition:opacity .15s;pointer-events:none;box-shadow:var(--shadow);
  z-index:2}
.axf:hover .axtip{opacity:1}

.axinp{flex:0 0 auto;display:flex;gap:9px;align-items:center;padding:11px 14px 13px}
.axinp .axtxt{flex:1;height:36px;border:1px solid var(--line-strong);border-radius:10px;
  background:var(--surface);padding:0 12px;font-size:12.5px;color:var(--ink);
  font-family:var(--font);outline:none;transition:border-color .15s}
.axinp .axtxt::placeholder{color:var(--faint)}
.axinp .axtxt:focus{border-color:var(--accent)}
.axinp .axgo{width:36px;height:36px;border-radius:10px;background:var(--accent);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:15px;
  border:0;cursor:pointer;flex:0 0 auto;transition:opacity .15s}
.axinp .axgo:hover{opacity:.85}

/* =====================================================================
   THE WHOLE PAGE TAKES THE DROP  (.axveil)

   There is no drop box any more. A box that says "drop here" is a box
   that spends every second of every day telling you to do something you
   already did this morning — and it was eating the top of the page where
   the table should be. The page itself is the target; the veil only
   appears while a file is actually over the window.
   ===================================================================== */
.axveil{position:fixed;inset:0;z-index:200;display:none;
  align-items:center;justify-content:center;
  background:rgba(var(--pane-rgb),.72);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.axveil.axon{display:flex;animation:axin .12s ease-out}
.axveil .axbox{border:2px dashed var(--accent);border-radius:16px;padding:34px 46px;
  background:var(--surface);box-shadow:var(--shadow);text-align:center}
.axveil .axbox .axt{font-family:var(--display);font-size:17px;font-weight:650;color:var(--hot)}
.axveil .axbox .axs{font-size:12.5px;color:var(--muted);margin-top:6px}

/* narrow screens: she takes the bottom instead of the corner. Desktop is
   the target, but a 1100px work monitor with the pane at 376px still has
   to leave the table room to be a table. */
@media (max-width:820px){
  .axpane{right:10px;left:10px;bottom:10px;width:auto;height:min(60vh,460px)}
}
/* =====================================================================
   THE FILE TREE  (files.html)
   Every rule scoped under .axtree on purpose. The markup wants short
   names — .row, .nm, .sz, .note — and this sheet already spends those
   on other components. Scoping is the fix; specificity games are not.
   Tokens only, so the tree wears whichever skin is on.
   ===================================================================== */
.axtree{background:var(--panel-a);border:1px solid var(--line-strong);border-radius:14px;
  padding:10px 6px;box-shadow:var(--shadow);font-family:var(--mono);font-size:13px;line-height:1.7}
.axtree .axrow{display:flex;align-items:center;gap:8px;padding:2px 12px;border-radius:var(--r-sm);
  white-space:nowrap;overflow:hidden}
.axtree .axrow:hover{background:var(--surface-2)}
.axtree .axtwist{width:12px;flex:0 0 auto;text-align:center;color:var(--muted-2);cursor:pointer;
  user-select:none}
.axtree .axic{width:16px;flex:0 0 auto;text-align:center}
.axtree .axnm{flex:0 0 auto;color:var(--ink)}
.axtree .axnm.axdir{color:var(--accent);font-weight:600;cursor:pointer}
.axtree .axcnt{flex:0 0 auto;font-family:var(--font);font-size:11px;color:var(--muted-2)}
.axtree .axnote{font-family:var(--font);font-size:11.5px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis}
.axtree .axsz{margin-left:auto;flex:0 0 auto;padding-left:12px;font-size:11px;color:var(--muted-2);
  font-variant-numeric:tabular-nums}
.axtree .axkids.hidden{display:none}
.axtree .axvend{font-family:var(--font);font-size:10px;color:var(--muted-2);
  border:1px solid var(--line-2);border-radius:20px;padding:0 6px;flex:0 0 auto}

/* file-type colours — the dot of colour is the only decoration here */
.axtree .t-html{color:var(--pink)}
.axtree .t-js{color:var(--amber)}
.axtree .t-css{color:var(--violet)}
.axtree .t-json{color:var(--mint)}
.axtree .t-sql{color:var(--accent-dim)}
.axtree .t-other{color:var(--muted-2)}

/* the one-line strip of numbers above the tree */
.axtreebar{display:flex;flex-wrap:wrap;gap:22px;align-items:baseline;margin:0 0 14px}
.axtreebar .n{font-family:var(--display);font-size:22px;font-weight:700;color:var(--hot);
  font-variant-numeric:tabular-nums}
.axtreebar .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-left:7px}

/* the legend */
.axtreekey{display:flex;flex-wrap:wrap;gap:9px 16px;margin:14px 0 0;font-family:var(--font);
  font-size:11.5px;color:var(--muted)}
.axtreekey span{display:inline-flex;align-items:center;gap:6px}
.axtreekey i{width:9px;height:9px;border-radius:2px;display:inline-block;background:currentColor}

/* ====================================================================
   LIFTED OUT OF PAGES (2026-07-27)
   Each rule below was written out separately in two or more pages with
   identical declarations. One copy lives here now; the copies are gone.
   What only LOOKED shared was deliberately left where it was — four pages
   spell .grid four different ways, and that wants renaming, not sharing.
   Nothing here newly reaches tools/placards: the printed placard is
   mandated and was proven byte-identical before and after.
   ==================================================================== */
.blank{display:inline-block;border-bottom:1px solid #000;min-width:70px}
.btn-row .btn-accent{flex:1}
.prev-head .hint{font-size:12px;color:var(--muted-2)}
.sec-h::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--line-strong),transparent)}

/* print: the screen chrome comes off the paper. */
@media print{
  /* Scoped to .app on purpose. The four tools all wrap in .app; the style
     guide shows a menubar and a statusbar as SWATCHES and must keep showing
     them. Unscoped, these hid the styleguide's own examples — caught by the
     before/after dump, not by looking. */
  .app .appbar{display:none!important}
  .app .col-left{display:none!important}
  .app .menubar{display:none!important}
  .app .modal-scrim{display:none!important}
  .app .prev-head{display:none!important}
  .app .statusbar{display:none!important}
}

/* =====================================================================
   THE SOI GRID  (soi.html)
   Scoped under .axsoigrid on purpose — this markup wants short names
   and the sheet already spends .row/.head/.tot on other components.
   Tokens only, so it wears either skin.
   ===================================================================== */
.axsoigrid{background:var(--panel-a);border:1px solid var(--line-strong);border-radius:14px;
  padding:6px 0 10px;box-shadow:var(--shadow);overflow-x:auto}
.axsoigrid .axsoirow{display:flex;align-items:stretch;min-width:max-content}
/* border-box on the cells, or the 74px basis and the 10px padding ADD and
   every column comes out 94px — the row ran 1101px inside a 998px panel and
   pushed the "all" total clean off the right edge. The sheet does not own a
   global box-sizing (nine pages each set their own), so this component states
   its own until that gap is closed properly. */
.axsoigrid .axsoik,
.axsoigrid .axsoic{box-sizing:border-box}
.axsoigrid .axsoik{flex:0 0 132px;padding:7px 14px;font-family:var(--mono);font-size:12px;
  color:var(--ink);letter-spacing:.03em;display:flex;align-items:center;position:sticky;left:0;
  background:var(--panel-a)}
.axsoigrid .axsoic{flex:0 0 74px;padding:7px 10px;text-align:right;font-family:var(--mono);
  font-size:13px;color:var(--ink);font-variant-numeric:tabular-nums}
.axsoigrid .axsoihead .axsoic{font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);border-bottom:1px solid var(--line)}
.axsoigrid .axsoihead .axsoik{border-bottom:1px solid var(--line)}
.axsoigrid .axsoirow:not(.axsoihead):hover{background:var(--surface-2)}
.axsoigrid .axsoizero{color:var(--muted-2)}
.axsoigrid .axsoitot{font-weight:600;color:var(--hot);border-left:1px solid var(--line)}
/* the worked-out row reads differently from a measured one on purpose */
.axsoigrid .axsoicalc .axsoik,
.axsoigrid .axsoicalc .axsoic{color:var(--mint)}
/* the hairline that keeps a photograph from being read as a movie */
.axsoigrid .axsoiband{margin:10px 14px 2px;padding-top:10px;border-top:1px solid var(--line-strong);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted-2)}
.axsoigrid .axsoiband:first-child{margin-top:2px;padding-top:0;border-top:0}


/* =====================================================================
   THE QUIET TELL  (.axtell) — a report page's own diagnostics, folded.
   A table page should show the table. But the notes underneath are what
   make a wrong column visible, so they collapse rather than disappear:
   the summary carries the counts, the detail is one click behind it.
   .legend and .hidden-note keep their own rules and are untouched —
   structure-map.html uses .legend too.
   ===================================================================== */
.axtell{margin:10px 2px 0}
.axtell>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:6px;
  font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--muted-2);
  padding:3px 0;user-select:none;transition:color .15s}
.axtell>summary::-webkit-details-marker{display:none}
.axtell>summary::before{content:"\25B8";display:inline-block;transition:transform .15s;font-size:9px}
.axtell[open]>summary::before{transform:rotate(90deg)}
.axtell>summary:hover{color:var(--ink)}
.axtell[open]>summary{color:var(--muted)}
