/* ============================================================================
   Lookling FBM — shared stylesheet
   ----------------------------------------------------------------------------
   Replaces the Metro UI CDN stylesheet. Written to be shared across the pages
   in fbm/public; index.html is the first page on it. Note that style.css is a
   separate, older sheet still used by watches.html — leave that one alone.
   ============================================================================ */

@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

/* :host as well as :root so the tokens reach the price-suggestion dialog, which
   the book page on the java server mounts inside a shadow root (see the wand
   section at the end). Inside a shadow tree :root matches nothing. */
:root, :host {
  /* surfaces */
  --bg:            #fafafa;
  --surface:       #ffffff;
  --surface-head:  #fbfbfc;
  --surface-sunk:  #f6f8fa;
  --surface-inset: #f0f1f3;

  /* lines */
  --line:          #e4e6ea;
  --line-soft:     #eef0f2;

  /* ink */
  --ink:           #1c1f24;
  --ink-2:         #3d4147;
  --ink-3:         #5b6068;
  --ink-muted:     #8a8f98;
  --ink-faint:     #9aa1ab;
  --ink-ghost:     #c2c5cb;

  /* accent + semantics */
  --accent:        #3a6fb0;
  --accent-dark:   #234a7c;
  --accent-wash:   #e9eef7;
  --good:          #5b8c5a;
  --danger:        #c0392b;
  --danger-ink:    #b23c3c;
  --danger-wash:   #fdf7f6;
  --warn-wash:     #f4e6d8;
  --warn-ink:      #b3895c;

  /* geometry */
  --r-sm: 4px;
  --r:    6px;
  --r-lg: 8px;
  --r-xl: 12px;

  --font: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

*, *::before, *::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

/* All font sizes below are rem, written as original-design-px / 16, so a
   user's browser font-size preference applies; the old px sizes ignored it.
   The html rule then scales the whole ramp up so the 13.5px design base
   renders at 18px (18 / 13.5 = 133.33%) — every rem value below grows by
   the same factor. Set this back to 100% to see the original design sizes. */
html { font-size: 133.3333%; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 0.84375rem;  /* design 13.5px, renders 18px */
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-dark); text-decoration: underline; }

.mono { font-family: var(--mono); }

/* ============================================================================
   App header + tabs
   ============================================================================ */

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 32px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.app-brand { display: flex; align-items: baseline; gap: 10px; }
.app-brand strong { font-size: 1.1875rem; font-weight: 700; letter-spacing: -0.01em; }
.app-brand span   { font-size: 0.8125rem; color: var(--ink-muted); }

.app-meta { display: flex; align-items: center; gap: 20px; }
.app-who { font-size: 0.8125rem; color: var(--ink-3); }

.app-user { font-size: 0.8125rem; font-weight: 600; color: var(--ink-2); }
.app-user .k { font-weight: 400; color: var(--ink-muted); }
.app-user.none { font-weight: 400; color: var(--ink-faint); font-style: italic; }

.app-tabs {
  display: flex;
  gap: 28px;
  padding: 0 32px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.app-tab {
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  padding: 14px 2px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.app-tab:hover { color: var(--ink-2); }
.app-tab .count { color: var(--ink-ghost); font-weight: 400; margin-left: 2px; }

.app-tab.is-active { color: var(--ink); font-weight: 600; border-bottom-color: var(--accent); }
.app-tab.is-active .count { color: var(--accent); font-weight: 600; }

.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

/* ============================================================================
   Toolbar
   ============================================================================ */

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px 16px;
  padding: 16px 32px;
}

.toolbar-main { display: flex; align-items: center; gap: 12px; }

.search { position: relative; }
.search svg {
  position: absolute;
  left: 11px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-faint);
  pointer-events: none;
}
.search input {
  width: 320px;
  padding: 8px 12px 8px 32px;
  border: 1px solid #d8dbe0;
  border-radius: var(--r);
  font-family: inherit;
  font-size: 0.8125rem;
  color: var(--ink);
  background: var(--surface);
}
.search input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(58, 111, 176, 0.12);
}

.toolbar-note { font-size: 0.8125rem; color: var(--ink-muted); }

/* Switch-style toggle, sized to sit level with the search field. */
.toggle {
  appearance: none;
  font: inherit;
  font-size: 0.78125rem;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 14px 7px 11px;
  border: 1px solid #d8dbe0;
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-muted);
  cursor: pointer;
  white-space: nowrap;
}
.toggle:hover { border-color: #b9bec6; }
.toggle:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(58, 111, 176, 0.16); }

.toggle .sw {
  position: relative;
  flex: none;
  width: 26px;
  height: 15px;
  border-radius: 999px;
  background: var(--ink-ghost);
  transition: background 0.12s ease;
}
.toggle .sw::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #fff;
  transition: transform 0.12s ease;
}

.toggle.is-on { color: var(--ink); border-color: #bfd0e6; background: var(--accent-wash); }
.toggle.is-on .sw { background: var(--accent); }
.toggle.is-on .sw::after { transform: translateX(11px); }

/* ============================================================================
   Grid table
   ============================================================================ */

.gt {
  margin: 0 32px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
}

.gt-head,
.gt-row {
  display: grid;
  grid-template-columns: var(--cols);
  column-gap: 12px;
  align-items: center;
  padding: 9px 14px;
}

.gt-head {
  background: var(--surface-head);
  border-bottom: 1px solid var(--line);
  padding-top: 10px;
  padding-bottom: 10px;
}

.gt-th {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 0.71875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
}
.gt-th.sortable { cursor: pointer; user-select: none; }
.gt-th.sortable:hover { color: var(--ink-2); }
.gt-th .arrows { flex: none; opacity: 0.35; }
.gt-th.sorted { color: var(--accent); }
.gt-th.sorted .arrows { opacity: 1; }

.gt-item { border-bottom: 1px solid var(--line-soft); }
.gt-item:last-child { border-bottom: 0; }

.gt-row { cursor: pointer; }
.gt-row:hover { background: var(--surface-head); }
.gt-flat .gt-row { cursor: default; }
.gt-item.flagged > .gt-row { background: var(--danger-wash); }
.gt-item.flagged > .gt-row:hover { background: #fbf0ee; }

.gt-chev { color: #b6bac1; display: flex; transition: transform 0.12s ease; }
.gt-item.open .gt-chev { transform: rotate(90deg); color: var(--accent); }

.gt-title {
  font-size: 0.84375rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.gt-item.open .gt-title { font-weight: 600; }

.gt-sub  { font-size: 0.78125rem; color: var(--ink-3); }
.gt-num  { font-family: var(--mono); font-size: 0.8125rem; font-weight: 600; }
.gt-code { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3); }
.gt-none { color: var(--ink-ghost); }

/* cover thumbnail */
.cover {
  width: 32px;
  height: 42px;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--accent-wash);
  display: block;
}
.cover-ph {
  width: 32px;
  height: 42px;
  border-radius: var(--r-sm);
  background: var(--accent-wash);
  color: #7089b3;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* status */
.status { display: flex; align-items: center; gap: 6px; font-size: 0.78125rem; color: var(--ink-3); }
.status .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--good); flex: none; }
.status.bad { color: var(--danger-ink); font-weight: 500; }
.status.bad .dot { background: var(--danger); }

/* row link buttons */
.gt-links { display: flex; align-items: center; gap: 8px; }
.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-faint);
  border-radius: var(--r-sm);
}
.icon-link:hover { color: var(--accent); text-decoration: none; }
.icon-link img,
.icon-link .amz {
  width: 19px;
  height: 19px;
  border-radius: 5px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06);
  display: block;
}
/* The Amazon mark carries its own colours, so hover reads as a lift instead. */
.icon-link .amz { opacity: 0.9; transition: opacity 0.12s ease; }
.icon-link:hover .amz { opacity: 1; }

/* ============================================================================
   Expanded detail panel
   ============================================================================ */

.gt-detail {
  display: none;
  gap: 32px;
  padding: 26px 30px 30px 82px;
  background: var(--surface-sunk);
  border-top: 1px solid var(--line);
}
.gt-item.open .gt-detail { display: flex; }

.detail-cover {
  width: 160px;
  min-height: 210px;
  border-radius: var(--r-xl);
  background: linear-gradient(160deg, #eef1f5, #e2e7ee);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  overflow: hidden;
  color: #a5aebd;
}
.detail-cover img { width: 100%; display: block; }
.detail-cover span { font-size: 0.6875rem; color: var(--ink-faint); }

.detail-body { flex: 1; min-width: 0; }

.detail-title { font-size: 1.1875rem; font-weight: 600; margin-bottom: 6px; }

.detail-headline {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 22px;
}
.detail-price { font-family: var(--mono); font-size: 1.3125rem; font-weight: 700; }

/* Storage box, sized to sit level with the price it stands next to. */
.detail-box {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 1.3125rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--accent);
}
.detail-box svg { flex: none; opacity: 0.6; }
.detail-box:hover { color: var(--accent-dark); }
.detail-box:hover svg { opacity: 0.9; }

.detail-box.empty {
  font-family: var(--font);
  font-size: 0.8125rem;
  font-weight: 600;
}
.detail-box.is-static { cursor: default; color: var(--ink-2); }
.detail-box.is-static:hover { color: var(--ink-2); }
.detail-box.is-static:hover svg { opacity: 0.6; }

.chip {
  font-size: 0.71875rem;
  font-weight: 600;
  color: var(--ink-3);
  background: var(--surface-inset);
  padding: 3px 9px;
  border-radius: 10px;
  white-space: nowrap;
}
.chip.good { color: #3f6b3e; background: #e8f1e7; }
.chip.warn { color: var(--warn-ink); background: var(--warn-wash); }

.detail-facts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 40px;
  font-size: 0.8125rem;
  margin-bottom: 22px;
}
.fact {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 7px 0;
  border-bottom: 1px solid var(--line-soft);
}
.fact:last-child { border-bottom: 0; }
.fact .k { color: var(--ink-muted); white-space: nowrap; }
.fact .v { color: var(--ink); font-weight: 500; text-align: right; }

.detail-notes {
  border-left: 3px solid var(--accent);
  background: var(--surface);
  border-radius: 0 var(--r) var(--r) 0;
  padding: 12px 16px;
  margin-bottom: 22px;
}
.detail-notes h4 {
  margin: 0 0 7px;
  font-size: 0.65625rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}
.detail-notes p { margin: 0 0 6px; font-size: 0.8125rem; color: var(--ink-2); line-height: 1.55; }
.detail-notes p:last-child { margin-bottom: 0; }

.detail-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

.round-link {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid #d8dbe0;
  background: var(--surface);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-3);
}
.round-link:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.round-link img,
.round-link .amz { width: 18px; height: 18px; border-radius: var(--r-sm); display: block; }

/* ============================================================================
   Buttons
   ============================================================================ */

.btn {
  appearance: none;
  font: inherit;
  font-size: 0.78125rem;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: var(--r);
  border: 1px solid #d8dbe0;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { border-color: #b9bec6; background: var(--surface-head); }
.btn:disabled,
.btn:disabled:hover { opacity: 0.45; cursor: default; }

.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); }

.btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { background: #a5301f; border-color: #a5301f; }

/* Used on its own, without .btn, in grid cells — so it carries the base button
   reset itself, including the pointer cursor. */
.btn-quiet {
  appearance: none;
  font: inherit;
  font-size: 0.78125rem;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: var(--r);
  background: none;
  color: var(--accent);
  padding: 4px 6px;
  margin-left: -6px;
  text-align: left;
  white-space: nowrap;
}
.btn-quiet:hover { background: var(--accent-wash); border-color: transparent; }
.btn-quiet.status.bad:hover { background: #f7e6e3; }

/* ============================================================================
   Modal
   ============================================================================ */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(28, 31, 36, 0.42);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 900;
}
.modal-backdrop[hidden] { display: none; }

.modal {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.22);
  width: 100%;
  max-width: 440px;
  overflow: hidden;
}
.modal h3 {
  margin: 0;
  padding: 16px 20px;
  font-size: 0.9375rem;
  font-weight: 600;
  border-bottom: 1px solid var(--line);
}
.modal-body { padding: 18px 20px; font-size: 0.84375rem; color: var(--ink-2); line-height: 1.55; }
.modal-body label { display: block; font-size: 0.78125rem; color: var(--ink-muted); margin-bottom: 6px; }
.modal-body input[type="text"],
.modal-body input[type="password"] {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid #d8dbe0;
  border-radius: var(--r);
  font-family: inherit;
  font-size: 0.84375rem;
  color: var(--ink);
}
.modal-body input[type="text"]:focus,
.modal-body input[type="password"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(58, 111, 176, 0.12);
}
.modal-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 14px 20px;
  background: var(--surface-head);
  border-top: 1px solid var(--line);
}
/* Pushes the optional third button (Sign Out, Remove From Shipment) away from
   Cancel/OK, so a destructive action is never next to the one people reach for. */
.modal-spacer { flex: 1; }

.modal-field { margin-top: 14px; }

.modal-error {
  margin: 0 20px 14px;
  padding: 8px 11px;
  border-radius: var(--r);
  background: var(--danger-wash);
  border: 1px solid #e8c9c3;
  color: var(--danger-ink);
  font-size: 0.78125rem;
  font-weight: 500;
}
.modal-error[hidden] { display: none; }

.modal-wide { max-width: 620px; }

/* ============================================================================
   States
   ============================================================================ */

.state {
  padding: 44px 20px;
  text-align: center;
  color: var(--ink-faint);
  font-size: 0.84375rem;
}

/* ============================================================================
   Book Finder — cover, title, boxes; deliberately not a grid
   ============================================================================ */

.finder-result {
  padding: 4px 32px 32px;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-2);
}
.finder-result p { margin: 10px 0 0; }
.finder-result .muted { color: var(--ink-muted); }
.finder-result strong { white-space: nowrap; }

.finder-card { display: flex; align-items: flex-start; gap: 28px; }
.finder-body { flex: 1; min-width: 0; }

/* Reports live in their own document (reports.html) on this same stylesheet, so
   the frame only has to be seamless: no border, no inner scrollbar. The height is
   set from the report's own content height, posted up on every render. */
.report-frame {
  display: block;
  width: 100%;
  height: 760px;
  border: 0;
}

/* ============================================================================
   Reports page — chart
   ============================================================================ */

.report-page { padding-bottom: 24px; }

.chart-card {
  margin: 20px 32px 0;
  padding: 16px 20px 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

.chart-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 24px;
  margin-bottom: 12px;
}
.chart-title { margin: 0; font-size: 0.9375rem; font-weight: 600; }
.chart-sub { font-size: 0.78125rem; color: var(--ink-muted); }

/* Legend doubles as the series filter, so each entry is a button. Colour follows
   the year, not its position, and stays put when other years are switched off. */
.legend { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.legend-item {
  appearance: none;
  font: inherit;
  font-size: 0.78125rem;
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 10px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink-2);
}
.legend-item:hover { background: var(--surface-inset); }
/* The series colour arrives as --sw rather than an inline background, so the
   switched-off rule below can override it without !important. */
.legend-item .sw { width: 10px; height: 10px; border-radius: 3px; flex: none; background: var(--sw); }
.legend-item.is-off { color: var(--ink-ghost); }
.legend-item.is-off .sw { background: transparent; box-shadow: inset 0 0 0 1.5px currentColor; }

.chart-plot { position: relative; }
.chart-plot svg { display: block; width: 100%; }

.ch-band  { fill: var(--surface-sunk); }
.ch-grid  { stroke: var(--line-soft); stroke-width: 1; }
.ch-axis  { stroke: var(--line); stroke-width: 1; }
.ch-tick  { fill: var(--ink-faint); font-family: var(--mono); font-size: 0.6875rem; }
.ch-month { fill: var(--ink-muted); font-size: 0.71875rem; font-weight: 500; }
.ch-month.is-sel { fill: var(--ink); font-weight: 600; }
.ch-hit   { fill: transparent; cursor: pointer; }

.chart-tip {
  position: absolute;
  z-index: 5;
  pointer-events: none;
  transform: translate(-50%, -100%);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.10);
  padding: 8px 11px;
  font-size: 0.78125rem;
  white-space: nowrap;
}
.chart-tip[hidden] { display: none; }
.chart-tip .tip-head { font-weight: 600; margin-bottom: 3px; }
.chart-tip .tip-row {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-weight: 600;
}
.chart-tip .tip-row .sw { width: 9px; height: 9px; border-radius: 2px; flex: none; }
.chart-tip .tip-sub { color: var(--ink-muted); margin-top: 1px; }

.chart-empty { padding: 40px 0 46px; text-align: center; color: var(--ink-faint); }

/* Heading over the month's book list. */
.section-head { padding: 20px 32px 0; }
.section-head h2 { margin: 0; font-size: 0.9375rem; font-weight: 600; }
.section-head .sub { font-size: 0.78125rem; color: var(--ink-muted); }
.section-head .sub .amt { font-family: var(--mono); font-weight: 600; color: var(--ink-2); }

/* ============================================================================
   Shipping station
   ----------------------------------------------------------------------------
   shipping.html is a single-purpose station rather than a list page: one open
   shipment, a scan field, and the boxes it is being packed into. It shares the
   grid and the modal with the rest of fbm/public; everything below is the part
   that is only shipping's.
   ============================================================================ */

/* The whole site signs in through the same 'who' cookie, but shipping is the
   page that owns signing in and out, so its name in the header is a button. */
.app-signin {
  appearance: none;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 13px;
  border: 1px solid #d8dbe0;
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
}
.app-signin:hover { border-color: var(--accent); color: var(--accent); }
.app-signin .k { font-weight: 400; color: var(--ink-muted); }
.app-signin.none { font-weight: 500; color: var(--danger-ink); border-color: #e2c4bf; background: var(--danger-wash); }

/* Progress strip. Shipping runs one way through four stages and a shipment
   that is stuck is the single most common support question, so the stage the
   shipment is actually in is stated rather than implied by which buttons show. */
.stages {
  display: flex;
  align-items: stretch;
  gap: 0;
  padding: 0 32px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.stages[hidden] { display: none; }

.stage {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 20px 11px 0;
  font-size: 0.8125rem;
  color: var(--ink-ghost);
  white-space: nowrap;
}
.stage + .stage { padding-left: 20px; }
.stage + .stage::before {
  content: '';
  flex: none;
  width: 6px;
  height: 6px;
  margin-left: -26px;
  margin-right: 12px;
  border-right: 1.5px solid var(--line);
  border-top: 1.5px solid var(--line);
  transform: rotate(45deg);
}
.stage .pip {
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.65625rem;
  font-weight: 700;
  font-family: var(--mono);
}
.stage.is-done { color: var(--good); }
.stage.is-done .pip { background: var(--good); border-color: var(--good); color: #fff; }
.stage.is-now { color: var(--ink); font-weight: 600; }
.stage.is-now .pip { background: var(--accent); border-color: var(--accent); color: #fff; }
/* A stage that is running rather than waiting for a person. */
.stage.is-busy .pip { animation: stage-pulse 1.4s ease-in-out infinite; }
@keyframes stage-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* Notices. The station is used at arm's length, so these are bigger than the
   toolbar notes on the list pages and hold their space. */
.notice {
  margin: 16px 32px 0;
  padding: 11px 15px;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 0.84375rem;
  display: flex;
  align-items: flex-start;
  gap: 9px;
}
.notice[hidden] { display: none; }
.notice svg { flex: none; margin-top: 2px; }
.notice.bad { background: var(--danger-wash); border-color: #e8c9c3; color: var(--danger-ink); font-weight: 500; }
.notice.good { background: #f2f7f2; border-color: #cfe0ce; color: #3f6b3e; }
/* The same block reused inside a dialog, where the page margins do not apply. */
.modal-body .notice { margin: 0 0 12px; font-size: 0.8125rem; }

/* Scan card. The field is the one thing a shipper touches all day, so it is
   the largest control on the page and always holds focus. */
.scan-card {
  display: flex;
  align-items: center;
  gap: 24px;
  margin: 16px 32px 0;
  padding: 20px 24px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.scan-card[hidden] { display: none; }

.scan-main { flex: 1; min-width: 0; }
.scan-label {
  font-size: 0.71875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 8px;
}
.scan-input {
  width: 100%;
  max-width: 460px;
  padding: 11px 15px;
  border: 1px solid #cfd4da;
  border-radius: var(--r);
  font-family: var(--mono);
  font-size: 1.0625rem;
  color: var(--ink);
  background: var(--surface);
}
.scan-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(58, 111, 176, 0.14);
}

/* Result of the last scan. The text and its colour both come from the book
   page on the java server, posted up out of the hidden frame, so the colour
   stays inline and only the frame around it belongs to this stylesheet. */
.scan-msg {
  margin-top: 12px;
  font-size: 0.9375rem;
  line-height: 1.45;
  min-height: 22px;
}
.scan-msg:empty { display: none; }

.scan-cover {
  flex: none;
  width: 96px;
  min-height: 124px;
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, #eef1f5, #e2e7ee);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  color: #a5aebd;
}
.scan-cover img { width: 100%; display: block; }

/* Row of station actions under the scan card. */
.actionbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 16px 32px 4px;
}
.actionbar .btn { display: inline-flex; align-items: center; gap: 7px; padding: 8px 14px; font-size: 0.8125rem; }
.actionbar .spacer { flex: 1; }
/* Both of these carry an explicit display, which otherwise beats the browser's
   own [hidden] rule and leaves a hidden element on screen. */
.actionbar[hidden] { display: none; }
.actionbar .btn[hidden] { display: none; }

.station-state {
  padding: 14px 32px 0;
  font-size: 0.84375rem;
  color: var(--ink-3);
}
.station-state strong { color: var(--ink); font-weight: 600; }

/* Boxes grid — the pieces the copy grids on the other pages do not have. */
.box-name { display: flex; align-items: center; gap: 9px; font-size: 0.875rem; font-weight: 600; }
.box-name .ico { color: var(--ink-faint); display: flex; }
.gt-item.open .box-name .ico,
.box-name.is-open .ico { color: var(--accent); }

.box-rejects { color: var(--danger-ink); font-weight: 600; font-size: 0.78125rem; }

.label-link { display: inline-flex; align-items: center; gap: 6px; font-size: 0.78125rem; font-weight: 500; }

/* The book list inside an expanded box. Titles are buttons: they open the
   book's details, which is where a book can be taken back out of a shipment. */
.gt-detail.booklist {
  display: none;
  flex-direction: column;
  gap: 0;
  padding: 8px 30px 14px 46px;
}
.gt-item.open .gt-detail.booklist { display: flex; }

.book-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.8125rem;
}
.book-row:last-child { border-bottom: 0; }
.book-row .n {
  flex: none;
  width: 26px;
  font-family: var(--mono);
  font-size: 0.71875rem;
  color: var(--ink-ghost);
  text-align: right;
}
.book-row .t {
  appearance: none;
  font: inherit;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  color: var(--accent);
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.book-row .t:hover { text-decoration: underline; }
.book-row .note { font-size: 0.75rem; color: var(--ink-muted); }
.book-row.is-reject .t { color: var(--ink-muted); text-decoration: line-through; }
.book-row .rm {
  appearance: none;
  font: inherit;
  border: 0;
  background: none;
  padding: 2px 4px;
  cursor: pointer;
  color: var(--danger);
  display: inline-flex;
  border-radius: var(--r-sm);
}
.book-row .rm:hover { background: #f7e6e3; }

.book-empty { font-size: 0.8125rem; color: var(--ink-faint); padding: 4px 0; }

/* Book details, shown in the modal. */
.bookinfo { display: flex; gap: 20px; }
.bookinfo img { width: 150px; border-radius: var(--r); background: var(--surface-inset); display: block; }
.bookinfo .facts { flex: 1; min-width: 0; }
.bookinfo .facts .fact:first-child { padding-top: 0; }

/* Box dimensions form. */
.dims-presets { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.dims-preset {
  appearance: none;
  font: inherit;
  font-size: 0.78125rem;
  font-weight: 500;
  cursor: pointer;
  padding: 6px 12px;
  border: 1px solid #d8dbe0;
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
}
.dims-preset:hover { border-color: #b9bec6; }
.dims-preset.is-on { background: var(--accent-wash); border-color: #bfd0e6; color: var(--accent-dark); font-weight: 600; }

.dims-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.dims-grid label { display: block; font-size: 0.71875rem; color: var(--ink-muted); margin-bottom: 5px; }
.dims-grid input {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid #d8dbe0;
  border-radius: var(--r);
  font-family: var(--mono);
  font-size: 0.875rem;
  color: var(--ink);
}
.dims-grid input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(58, 111, 176, 0.12);
}
.dims-grid .unit { font-size: 0.6875rem; color: var(--ink-faint); margin-top: 4px; }

/* ============================================================================
   Simple stations — relabelling, send-to helper, green tags
   ============================================================================ */

.page-body { padding: 24px 32px; max-width: 900px; }
.page-body h2 { margin: 0 0 6px; font-size: 0.9375rem; font-weight: 600; }
.page-body p { margin: 0 0 16px; font-size: 0.84375rem; color: var(--ink-3); }

.tag-list { display: flex; flex-wrap: wrap; gap: 8px; }
.tag-chip {
  appearance: none;
  font: inherit;
  font-family: var(--mono);
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  padding: 9px 14px;
  border: 1px solid #d8dbe0;
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 9px;
}
.tag-chip:hover { border-color: var(--accent); color: var(--accent); }
.tag-chip .when { font-family: var(--font); font-size: 0.6875rem; font-weight: 400; color: var(--ink-faint); }
.tag-chip.is-printed { background: var(--surface-sunk); color: var(--ink-muted); }
.tag-chip.is-printed:hover { color: var(--accent); }

.upload-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 20px; }
.upload-row input[type="file"] { font-size: 0.8125rem; }

/* Checkbox and dropdown cells, for the permissions grid. */
.gt-check { display: flex; justify-content: center; }
.gt-check input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
  margin: 0;
}

.mini-select {
  font: inherit;
  font-size: 0.78125rem;
  padding: 4px 8px;
  border: 1px solid #d8dbe0;
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  max-width: 100%;
}
.mini-select:focus { outline: none; border-color: var(--accent); }

.code-cell { display: flex; align-items: center; gap: 6px; }
.code-cell .code { font-family: var(--mono); font-size: 0.78125rem; font-weight: 600; }
.code-cell .clear {
  appearance: none;
  font: inherit;
  border: 0;
  background: none;
  padding: 2px 4px;
  cursor: pointer;
  color: var(--ink-ghost);
  display: inline-flex;
  border-radius: var(--r-sm);
}
.code-cell .clear:hover { color: var(--danger); background: #f7e6e3; }

/* These are labels inside a dialog, and `.modal-body label` above makes every
   label there a block-level field caption, so the rule has to be at least as
   specific to win. */
.role-list { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.modal-body .role-line {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 0;
  font-size: 0.8125rem;
  color: var(--ink-2);
  cursor: pointer;
}
.role-line input { accent-color: var(--accent); width: 15px; height: 15px; margin: 0; cursor: pointer; }

/* ============================================================================
   Narrow screens
   ============================================================================ */

@media (max-width: 1279px) {
  .app-header, .app-tabs, .toolbar, .section-head,
  .stages, .actionbar, .station-state, .page-body { padding-left: 20px; padding-right: 20px; }
  .gt, .chart-card, .notice, .scan-card { margin-left: 20px; margin-right: 20px; }
  .gt-detail { padding-left: 30px; }
  .gt-detail.booklist { padding-left: 34px; }
  .search input { width: 240px; }
}

@media (max-width: 900px) {
  .gt { overflow-x: auto; }
  .gt-head, .gt-row { min-width: 900px; }
  .gt-detail { flex-direction: column; }
  .gt-detail.booklist { flex-direction: column; }
  .detail-facts { grid-template-columns: 1fr; }
  .stages { overflow-x: auto; }
  .scan-card { flex-direction: column; align-items: stretch; }
  .scan-cover { align-self: flex-start; }
  .dims-grid { grid-template-columns: repeat(2, 1fr); }
  .bookinfo { flex-direction: column; }
}

/* ============================================================================
   Price suggestion dialog — the magic wand on the book page
   ----------------------------------------------------------------------------
   Opened from files/booklook.js next to the dollar-sign icon; the answer comes
   from fbm's /suggestprice route (the suggest-price skill run headlessly). The
   dialog is mounted inside a shadow root on the java-served book page so this
   sheet can style it without touching the rest of that page — which is why
   :root above is also :host, and why everything here is sized in em off one
   base rather than rem: rem there is the book page's 16px root, not the 18px
   this sheet assumes. The readers are volunteers on ordinary laptops, so the
   base is 18px and nothing drops below about 14px.
   ============================================================================ */

.wand {
  font-family: var(--font);
  font-size: clamp(16px, 1.125rem, 18px);
  line-height: 1.45;
  color: var(--ink);
  background: var(--surface);
  border: 0;
  padding: 0;
  border-radius: var(--r-xl);
  box-shadow: 0 16px 50px rgba(0, 0, 0, 0.28);
  width: min(46em, 94vw);
  max-height: 90vh;
  overflow: hidden;
}
.wand[open] { display: flex; flex-direction: column; }
.wand::backdrop { background: rgba(28, 31, 36, 0.45); }
/* showModal() focuses the dialog itself, and Chrome rings it. */
.wand:focus, .wand:focus-visible { outline: none; }
.wand * { box-sizing: border-box; }

.wand-head {
  display: flex;
  align-items: flex-start;
  gap: 1em;
  padding: 1em 1.25em 0.85em;
  border-bottom: 1px solid var(--line);
}
.wand-head .grow { flex: 1; min-width: 0; }
.wand-kicker {
  font-size: 0.72em;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 0.25em;
}
.wand-title { font-size: 1.15em; font-weight: 600; line-height: 1.3; }
.wand-sub { font-size: 0.85em; color: var(--ink-3); margin-top: 0.3em; }
.wand-sub .sep { color: var(--ink-ghost); margin: 0 0.4em; }
.wand-sub a { color: var(--accent); }
.wand-x {
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  font-size: 1.5em;
  line-height: 1;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 0.1em 0.35em;
  border-radius: var(--r);
  margin: -0.1em -0.3em 0 0;
}
.wand-x:hover { color: var(--ink); background: var(--surface-inset); }

/* Tabs and buttons reuse the page components; only their rem sizes are re-based. */
.wand .app-tabs { padding: 0 1.25em; gap: 1.6em; }
.wand .app-tab { font-size: 0.9em; padding: 0.7em 0.1em; }
.wand .btn { font-size: 0.9em; padding: 0.5em 1em; }
.wand .modal-actions { padding: 0.8em 1.25em; }
.wand .notice { margin: 0 0 1em; font-size: 0.92em; }

.wand-body { flex: 1; min-height: 0; overflow: auto; padding: 1.1em 1.25em 1.25em; }

/* Suggestion tab */
.wand-price-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.6em 1.2em;
  margin-bottom: 0.9em;
}
.wand-price {
  font-family: var(--mono);
  font-size: 2.2em;
  font-weight: 700;
  line-height: 1;
  color: var(--accent-dark);
  white-space: nowrap;
}
.wand-verdict { flex: 1; min-width: 14em; color: var(--ink-2); line-height: 1.5; }

.wand-h {
  font-size: 0.72em;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 1.1em 0 0.4em;
}
.wand-why { margin: 0; padding: 0; list-style: none; }
.wand-why li {
  position: relative;
  padding: 0.5em 0 0.5em 1.4em;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink-2);
  line-height: 1.5;
}
.wand-why li::before {
  content: '';
  position: absolute;
  left: 0.3em;
  top: 1.05em;
  width: 0.45em;
  height: 0.45em;
  border-radius: 50%;
  background: var(--accent);
}
.wand-why li:last-child { border-bottom: 0; }
.wand-raw {
  white-space: pre-wrap;
  font-family: inherit;
  margin: 0;
  color: var(--ink-2);
  line-height: 1.5;
}
.wand-foot { margin-top: 1.1em; font-size: 0.82em; color: var(--ink-muted); }
.wand-foot a { color: var(--accent); cursor: pointer; }

/* Prices tab */
.wand-ours {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3em 1.4em;
  padding: 0.7em 0.9em;
  margin-bottom: 1em;
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--r);
  font-size: 0.9em;
}
.wand-ours .k { color: var(--ink-muted); margin-right: 0.35em; }
.wand-ours .v { font-weight: 600; }
.wand-ours .mono { font-family: var(--mono); }

.wand-cond { margin-top: 1.1em; }
.wand-cond:first-of-type { margin-top: 0; }
.wand-cond-h { display: flex; align-items: baseline; gap: 0.6em; font-weight: 600; font-size: 0.95em; margin-bottom: 0.35em; }
.wand-cond-h .n { font-size: 0.82em; font-weight: 500; color: var(--ink-muted); }

.wand-tbl { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.wand-offers { width: 100%; border-collapse: collapse; font-size: 0.9em; }
.wand-offers td { padding: 0.45em 0.7em; border-top: 1px solid var(--line-soft); vertical-align: middle; }
.wand-offers tr:first-child td { border-top: 0; }
.wand-offers .num { font-family: var(--mono); font-weight: 700; white-space: nowrap; width: 5.5em; }
.wand-offers .brk { color: var(--ink-muted); white-space: nowrap; font-size: 0.9em; }
.wand-offers .who { color: var(--ink-2); }
.wand-offers .who .pct { color: var(--ink-muted); }
.wand-offers .tags { text-align: right; white-space: nowrap; }
.wand-offers tr.is-us td { background: #e8f1e7; }
.wand-offers tr.is-bb td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

.wand-chip {
  display: inline-block;
  font-size: 0.74em;
  font-weight: 600;
  line-height: 1.5;
  padding: 0.1em 0.65em;
  border-radius: 1em;
  background: var(--surface-inset);
  color: var(--ink-3);
  margin-left: 0.3em;
  white-space: nowrap;
  vertical-align: middle;
}
.wand-chip.bb  { background: var(--accent-wash); color: var(--accent-dark); }
.wand-chip.us  { background: #d7e8d6; color: #2f5a2e; }
.wand-chip.fba { background: #efe9f7; color: #5d3f8a; }
.wand-chip.amz { background: #fdeccf; color: #8a5a12; }

.wand-sibs { margin: 0; padding: 0; list-style: none; font-size: 0.92em; }
.wand-sibs li { padding: 0.4em 0; border-bottom: 1px solid var(--line-soft); color: var(--ink-2); }
.wand-sibs li:last-child { border-bottom: 0; }
.wand-sibs .mono { font-family: var(--mono); font-weight: 600; }

.wand-empty { padding: 1.5em 0; text-align: center; color: var(--ink-faint); }

/* Waiting state */
.wand-wait { padding: 2.4em 1.5em 2.2em; text-align: center; color: var(--ink-3); line-height: 1.5; }
.wand-wait img {
  width: 3.2em;
  height: 3.2em;
  display: block;
  margin: 0 auto 1em;
  transform-origin: 20% 85%;
  animation: wand-wave 1.6s ease-in-out infinite;
}
@keyframes wand-wave { 0%, 100% { transform: rotate(-10deg); } 50% { transform: rotate(12deg); } }
.wand-wait .big { font-size: 1.1em; font-weight: 600; color: var(--ink); margin-bottom: 0.35em; }
.wand-wait .timer { font-family: var(--mono); color: var(--ink-muted); margin-top: 0.7em; }
.wand-wait .small { font-size: 0.85em; color: var(--ink-muted); margin-top: 0.9em; }

@media (max-width: 640px) {
  .wand { width: 100vw; max-height: 100vh; border-radius: 0; }
  .wand-head, .wand-body, .wand .app-tabs, .wand .modal-actions { padding-left: 0.9em; padding-right: 0.9em; }
  .wand-offers .brk { display: none; }
}
