/* One stylesheet. Measured off Jifeng: dark navy bar, mega-menu panels on
   hover, pale grey page, white cards. */

:root {
  --bar: #16233f;
  --bar-hover: #22314f;
  --accent: #2563eb;
  --page: #f2f4f8;
  --card: #ffffff;
  --line: #e3e8ef;
  --ink: #1f2937;
  --ink-dim: #6b7280;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* ---- top bar ---------------------------------------------------------- */

.topbar {
  display: flex;
  align-items: stretch;
  background: var(--bar);
  color: #fff;
  height: 44px;
  position: relative;
  z-index: 20;
}

/* Spanish runs about a third longer than English and German longer still, so
   the bar is built to give way rather than to fit one language exactly: the
   brand and the account truncate, the headings tighten, and the language
   switcher and account stay put. Found by running the thing in Spanish, which
   is the only way this kind of bug is ever found. */

.brand {
  display: flex;
  align-items: center;
  padding: 0 20px;
  font-weight: 600;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 0 1 auto;
  min-width: 3rem;
}

.sections {
  display: flex;
  align-items: stretch;
  flex: 1 1 auto;
  min-width: 0;
}

.section { position: relative; display: flex; align-items: stretch; min-width: 0; }

.section-head {
  display: flex;
  align-items: center;
  padding: 0 16px;
  color: #dbe2f0;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The bar carries eight sections, a language switcher, an address and a way
   out. Which of those can go, in order, as it gets tight -- the address first
   because it is the only one that is merely informative. The switcher and the
   way out always stay: they are how somebody who is stuck gets unstuck. */

@media (max-width: 1400px) {
  .brand { padding: 0 12px; }
  .section-head { padding: 0 10px; }
  .account { max-width: 11rem; }
}

@media (max-width: 1180px) {
  .section-head { padding: 0 8px; font-size: 13px; }
  .account { display: none; }
}

@media (max-width: 900px) {
  .brand { padding: 0 8px; font-size: 13px; max-width: 9rem; }
  .section-head { padding: 0 6px; }
  .signout { margin-right: 8px; padding: 4px 8px; }
}

/* The corner icons. Same height as the bar so they line up with the section
   heads, and a hit area big enough for a finger -- this is the door to
   settings, not decoration. */
.iconbtn {
  display: flex;
  align-items: center;
  padding: 0 10px;
  color: #dbe2f0;
  text-decoration: none;
  flex: 0 0 auto;
}
.iconbtn:hover, .iconbtn.current { background: var(--accent); color: #fff; }

.section:hover .section-head,
.section-head.current { background: var(--accent); color: #fff; }

/* The panel is the section's own child, so it opens on hover and on keyboard
   focus alike, and there is no state to get stuck. */
.panel {
  display: none;
  position: absolute;
  top: 44px;
  left: 0;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 0 0 6px 6px;
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.14);
  padding: 18px 8px 20px;
  gap: 8px;
}

/* Panels near the right edge open leftwards, or they hang off the screen.
   Which sections are "near the right edge" is not a fixed number of items --
   the menu is filtered per tenant -- so it is counted from the end. */
.section:nth-last-child(-n + 3) .panel { left: auto; right: 0; }

.section:hover .panel,
.section:focus-within .panel { display: flex; }

.group { min-width: 168px; padding: 0 14px; }

.group-head {
  color: var(--ink-dim);
  font-size: 12px;
  font-weight: 600;
  padding: 0 0 10px 8px;
  border-left: 3px solid var(--accent);
  margin-bottom: 4px;
  line-height: 1;
  padding-top: 2px;
}

.item {
  display: block;
  padding: 7px 8px;
  color: var(--ink);
  text-decoration: none;
  border-radius: 4px;
  white-space: nowrap;
}

.item:hover { background: #eef2fb; color: var(--accent); }
.item.current { color: var(--accent); font-weight: 600; }

/* Locked: dimmed and badged, never disabled. It opens the upgrade screen, and
   a menu entry that looks dead is exactly what this system exists to avoid. */
.item.locked { color: var(--ink-dim); }
.item.locked::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 8px;
  margin-left: 7px;
  border-radius: 1px;
  background: currentColor;
  box-shadow: 0 -3px 0 -1px transparent, inset 0 0 0 8px currentColor;
  opacity: 0.55;
  vertical-align: -1px;
}
.item.locked:hover { color: var(--accent); background: #eef2fb; }

.account {
  display: flex;
  align-items: center;
  padding: 0 18px;
  color: #c8d2e6;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 0 1 auto;
  max-width: 14rem;
}

/* Language switcher. Sits in the bar next to the account, because that is
   where somebody who has landed in the wrong language goes looking. */
.lang {
  align-self: center;
  background: transparent;
  color: #dbe2f0;
  border: 1px solid #3a4767;
  border-radius: 5px;
  padding: 4px 8px;
  font: inherit;
  cursor: pointer;
  flex: 0 0 auto;
}
.lang:hover { background: var(--bar-hover); }
.lang option { color: var(--ink); background: #fff; }

.signout {
  align-self: center;
  background: transparent;
  color: #c8d2e6;
  border: 1px solid #3a4767;
  border-radius: 5px;
  padding: 4px 10px;
  margin-right: 12px;
  font: inherit;
  cursor: pointer;
  flex: 0 0 auto;
}
.signout:hover { background: var(--bar-hover); color: #fff; }

.nav-error { background: #fdecec; color: #b42318; padding: 10px 16px; }

/* ---- page ------------------------------------------------------------- */

main { padding: 20px 24px 40px; }

h1 { font-size: 19px; margin: 0 0 4px; }
.sub { color: var(--ink-dim); margin: 0 0 20px; }

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 18px 20px;
  margin-bottom: 16px;
}

/* A card holding a table scrolls inside itself. A column count that fits in
   English and not in Spanish must not push the whole page sideways. */
.card:has(> table) { padding: 0; overflow-x: auto; }

table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--line); }
th { color: var(--ink-dim); font-weight: 600; font-size: 12px; }
tbody tr:last-child td { border-bottom: 0; }

label { display: block; font-size: 12px; color: var(--ink-dim); margin-bottom: 4px; }

input[type="text"], input[type="email"] {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 5px;
  font: inherit;
}

button {
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 5px;
  padding: 8px 16px;
  font: inherit;
  cursor: pointer;
}
button:hover { background: #1d4fd8; }
button.ghost { background: #fff; color: var(--ink); border: 1px solid var(--line); }

.row { display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-end; }
.row > div { flex: 1 1 190px; }

.lines { display: flex; flex-wrap: wrap; gap: 10px 18px; }
.lines label { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink); margin: 0; }

.pill {
  display: inline-block;
  background: #eef2fb;
  color: #1d4fd8;
  border-radius: 10px;
  padding: 1px 9px;
  font-size: 12px;
  margin-right: 5px;
}
.pill.off { background: #f3f4f6; color: var(--ink-dim); }

.msg { padding: 9px 12px; border-radius: 5px; margin-bottom: 14px; }
.msg.ok { background: #ecfdf3; color: #027a48; }
.msg.bad { background: #fdecec; color: #b42318; }
/* ⚠ The third answer, and it is not a shade of failure. What we own worked and
   only an outward call did not -- a hand-over recorded but a carrier that
   refused. Reporting that in red sends somebody to undo a thing that is
   correct. Same colour, same reasoning, as the measuring station's amber. */
.msg.warn { background: #fff7ec; color: #a35f07; }

/* ---- status tabs ------------------------------------------------------- */

.tabs { display: flex; gap: 2px; margin-bottom: 14px; flex-wrap: wrap; }

.tab {
  background: transparent;
  color: var(--ink-dim);
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  padding: 8px 14px;
  font: inherit;
  cursor: pointer;
}
.tab:hover { background: transparent; color: var(--ink); }
.tab.on { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.tab .n { color: var(--ink-dim); font-weight: 400; margin-left: 2px; }
.tab.on .n { color: var(--accent); }

button.sm { padding: 4px 10px; font-size: 12px; }

/* ---- record status ----------------------------------------------------- */

.status {
  display: inline-block;
  border-radius: 10px;
  padding: 1px 9px;
  font-size: 12px;
  background: #f3f4f6;
  color: var(--ink-dim);
  /* A status that wraps one character per line is unreadable, and Chinese
     wraps anywhere. It keeps its width and the table scrolls instead. */
  white-space: nowrap;
}
.status.pending { background: #fff6e5; color: #b54708; }
.status.active { background: #ecfdf3; color: #027a48; }
.status.rejected { background: #fdecec; color: #b42318; }
.status.draft { background: #eef2fb; color: #1d4fd8; }

code { background: #f3f4f6; border-radius: 3px; padding: 1px 5px; font-size: 12px; }

/* ---- sign in ------------------------------------------------------------ */

/* The two screens with no session behind them, so no bar and nothing to
   navigate to. A centred card and a language switcher, because somebody who
   cannot read this page still has to be able to change it. */

/* Every page in this product is a pale page. The sign-in screens used to sit
   on the dark bar; they do not any more. */
body.plain { background: var(--page); }

.auth {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 24px;
}

.auth-card {
  width: 100%;
  max-width: 380px;
  margin: 0;
  padding: 28px 30px 30px;
}

.auth-card h1 { margin-bottom: 4px; }
.auth-card .sub { margin-bottom: 20px; }

input[type="password"] {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 5px;
  font: inherit;
}

.auth-lang { max-width: 380px; width: 100%; text-align: right; }
.lang.light { border-color: #3a4767; }

/* ---- numeric columns ------------------------------------------------------ */

/* Figures line up on the right and in a tabular font, so a column of them can
   be read down rather than one at a time. */
th.n, td.n { text-align: right; font-variant-numeric: tabular-nums; }

/* Zero is quieter than a number. */
.zero { color: #c3c9d4; }

/* Owed is loud. A shortfall reported as zero is the bug the ledger exists to
   prevent, so it is never allowed to look like nothing. */
.owed { color: #b42318; font-weight: 600; }

tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: #f7f9fd; }

/* ---- the weigh-and-ship bench --------------------------------------------- */

/* Sized for a person a metre from the screen who is holding a box. Nothing
   here is subtle on purpose. */

.bench-scan label { font-size: 13px; }
.bench-scan input {
  font-size: 26px;
  padding: 12px 14px;
  letter-spacing: 0.02em;
}

.bench-answer {
  border-radius: 8px;
  padding: 18px 22px;
  margin: 16px 0;
  border: 1px solid var(--line);
}
.bench-answer .big { font-size: 26px; font-weight: 600; line-height: 1.2; }
.bench-answer .small { margin-top: 4px; font-size: 14px; opacity: 0.85; }

.bench-answer.idle { background: var(--card); color: var(--ink-dim); }
.bench-answer.ok { background: #ecfdf3; border-color: #a6f4c5; color: #027a48; }
.bench-answer.bad { background: #fdecec; border-color: #fda29b; color: #b42318; }

.bench-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 14px; }
.bench-ref { font-size: 20px; font-weight: 600; }

#weight { font-size: 22px; padding: 10px 12px; }

.status.shipped { background: #ecfdf3; color: #027a48; }
.status.exception { background: #fdecec; color: #b42318; }
.status.cancelled { background: #f3f4f6; color: var(--ink-dim); }
.status.toShip, .status.toPack, .status.toPrint { background: #fff6e5; color: #b54708; }
.status.awaitingTracking { background: #eef2fb; color: #1d4fd8; }

/* A disabled control must look disabled.
   The whole system runs on "what you can see, you can use" -- a button that
   reads as clickable and does nothing is the same lie as a menu entry that
   opens nothing, just smaller. */
button:disabled,
button:disabled:hover {
  background: #eef0f4;
  color: #a8b0bd;
  border-color: var(--line);
  cursor: not-allowed;
}
button.ghost:disabled,
button.ghost:disabled:hover { background: #f7f8fa; color: #a8b0bd; }

input:disabled {
  background: #f7f8fa;
  color: var(--ink-dim);
  cursor: not-allowed;
}

/* ---- the factory measuring station ---------------------------------------- */

/* A page of its own, opened on a fixed machine at the seller's factory. It has
   no top bar because it has no account behind it -- see the head of
   web/station.html. Sized like the weighing bench, for the same reason: the
   person using it is holding a box, not reading. */

.station { max-width: 760px; margin: 0 auto; padding: 22px 20px 60px; }

.station-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.station-head h1 { margin: 0 0 4px; }
.station-who { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-dim); }

/* The weight is deliberately not one of four matching boxes: its own row, its
   own colour, away from the three sides. A length typed into the weight is a
   mistake nothing downstream can catch -- both numbers stay plausible and the
   freight is simply booked wrong. */
.station-weight {
  margin-top: 14px;
  background: #fff7ec;
  border: 1.5px solid #e0a458;
  border-radius: 8px;
  padding: 10px 12px 12px;
}
.station-weight label { color: #a35f07; font-weight: 600; }
.station-weight input { font-size: 26px; padding: 10px 12px; border-color: #e0a458; }

.station-dims { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 12px; }
.station-dims input { font-size: 20px; padding: 10px 8px; text-align: center; }

.station-go { width: 100%; margin-top: 16px; font-size: 17px; padding: 14px 20px; }

.station-row { padding: 10px 14px; margin-bottom: 8px; display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
.station-row .sub { margin: 0; }

/* Recorded, but the forwarder did not answer. Not green and not red: the
   measurement is ours and is safe, and only the push has to be tried again. */
.bench-answer.warn { background: #fff7ec; border-color: #e0a458; color: #a35f07; }

.status.measured { background: #eef2fb; color: #1d4fd8; }
.status.handedOver { background: #fff6e5; color: #b54708; }
.status.arrived { background: #ecfdf3; color: #027a48; }
.status.closed { background: #f3f4f6; color: var(--ink-dim); }

/* The switcher on the station page sits on a pale background, not on the dark
   bar it was drawn for. */
.station .lang { color: var(--ink); border-color: var(--line); }
.station .lang:hover { background: #eef2fb; }

/* One focus ring, and it is the accent colour -- not the browser's, which on
   some builds is amber and quietly competes with the weight box for the one
   piece of amber on the measuring station. */
input:focus-visible,
select:focus-visible,
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.station-weight input:focus-visible { outline-color: #a35f07; }
.station-who button { white-space: nowrap; }
.status.suspended { background: #fdecec; color: #b42318; }

/* --- what the seller's screens and the despatch bench needed --------------
 *
 * Added rather than worked around in each page: a screen that reaches for an
 * inline style because the stylesheet lacks a rule is a screen that looks
 * almost like the ones beside it, which is worse than looking different. */

/* Every text-ish input, not only the two the console happened to use first.
 * A search box that is 140px wide because nobody wrote the selector is the
 * commonest way a form looks unfinished. */
input[type="search"],
input[type="date"],
input[type="number"],
textarea {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 5px;
  font: inherit;
}
textarea { resize: vertical; }

/* A link that does a button's job. It has to look like one, because "new
 * product" sitting in a row of buttons as blue underlined text reads as a
 * footnote. It is an anchor and not a button because it navigates -- so it
 * opens in a new tab on a middle click, like every other link. */
a.button {
  display: inline-block;
  background: var(--accent);
  color: #fff;
  border-radius: 5px;
  padding: 8px 16px;
  text-decoration: none;
}
a.button:hover { background: #1d4fd8; }

/* Sent out, and it is a different ending from closed -- see
 * server/src/db/consignments.ts. Amber rather than green: the box has left the
 * building, which is finished but is not the same as finished-and-on-a-shelf. */
.status.despatched { background: #fff6e5; color: #b54708; }

/* A row carrying a debt. The figure inside it is already red; this is what
 * makes the row findable when the table is forty long. */
tr.warn td { background: #fffaf3; }

/* ⚠ The warehouse is working inside a seller's screens.
 *
 * Amber and impossible to miss, at the top of every page, for as long as it
 * lasts. Everything done here is filed under the operator's name and the seller
 * can read that list -- somebody cannot be expected to act as if they are on
 * the record unless the screen says so. */
.viewing {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  background: #fff6e5;
  color: #b54708;
  border-bottom: 1px solid #f0c36d;
  font-size: 13px;
}
.viewing span { color: #8a5a10; }
.viewing button { margin-left: auto; }
