/*
 * The admin shell: a fixed rail down the left, screens to the right of it.
 *
 * Same pattern as the Sideline backend, deliberately — it is the layout Romero
 * already operates daily, and a second navigation idiom to learn is a cost with
 * no matching benefit. What differs is only what the shape demands: open
 * tournaments nest under their section, because that is the thing jumped
 * between all season.
 *
 * Colours and the face come from brand.css, which was read off the live otx2.com
 * rather than sampled from a mockup. Nothing in this file invents a colour.
 *
 * BUILT DARK, and single-theme on purpose. The wordmark is white artwork with a
 * transparent ground, the live site is near-black, and an operator screen that
 * flipped to a white page in daylight would be a different product to the one
 * the brand describes. Every colour is therefore stated outright rather than
 * left to the host.
 */
@import url("/brand/brand.css");

* { box-sizing: border-box; }

:root {
  --rail: 260px;

  --bg:      var(--otx-black);
  --panel:   #17171A;
  --panel-2: #1D1E23;
  --edge:    rgba(255, 255, 255, .085);
  --edge-2:  rgba(255, 255, 255, .16);

  --txt:     #F4F5F7;
  --txt-2:   rgba(244, 245, 247, .62);
  --txt-3:   rgba(244, 245, 247, .38);

  --live:    #5A78E0;
  --live-bg: rgba(51, 79, 180, .18);
}

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--txt);
  font-family: var(--otx-face);
  font-size: 15px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--live); }

/* ── the rail ─────────────────────────────────────────────────────── */
.rail {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: var(--rail);
  background: var(--panel);
  border-right: 1px solid var(--edge);
  display: flex;
  flex-direction: column;
  z-index: 40;
}

.rail-brand {
  padding: 22px 20px 18px;
  border-bottom: 1px solid var(--edge);
  flex: none;
}
.rail-brand img { display: block; height: 26px; width: auto; }
.rail-brand span {
  display: block;
  margin-top: 9px;
  font-size: 10.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--txt-3);
}

.rail-nav {
  flex: 1;
  overflow-y: auto;
  padding: 12px 10px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nav-i {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 12px;
  border-radius: 7px;
  border: none;
  border-left: 3px solid transparent;
  background: none;
  color: var(--txt-2);
  font-size: 14px;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  width: 100%;
}
.nav-i:hover { background: rgba(255, 255, 255, .045); color: var(--txt); }
.nav-i.on {
  background: var(--live-bg);
  border-left-color: var(--otx-blue);
  color: #FFFFFF;
  font-weight: 600;
}
.nav-i svg { width: 17px; height: 17px; flex: none; opacity: .85; }
.nav-i .count {
  margin-left: auto;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--txt-3);
  background: rgba(255, 255, 255, .07);
  border-radius: 20px;
  padding: 1px 7px;
}

/* Open tournaments, nested. Indented to the icon column so the hierarchy reads
   without a second border or a disclosure triangle. */
.nav-sub {
  display: block;
  padding: 6px 12px 6px 43px;
  border-radius: 6px;
  border-left: 3px solid transparent;
  color: var(--txt-3);
  font-size: 13px;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nav-sub:hover { color: var(--txt); background: rgba(255, 255, 255, .04); }
.nav-sub.on { color: #FFFFFF; border-left-color: var(--otx-blue); background: var(--live-bg); }

.rail-foot {
  flex: none;
  padding: 14px 20px 16px;
  border-top: 1px solid var(--edge);
  font-size: 12px;
  color: var(--txt-3);
}
.rail-foot .who { word-break: break-all; margin-bottom: 8px; }
.rail-foot button {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--txt-2); font-size: 13px; text-decoration: underline;
}

/* ── main ─────────────────────────────────────────────────────────── */
.main { margin-left: var(--rail); min-height: 100vh; }
.main-in { max-width: 1180px; padding: 30px 32px 80px; }

.topbar {
  display: none;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--edge);
  background: var(--panel);
  position: sticky; top: 0; z-index: 30;
}
.topbar img { height: 20px; width: auto; }
.burger {
  background: none; border: 1px solid var(--edge-2); border-radius: 7px;
  padding: 6px 9px; cursor: pointer; line-height: 0;
}
.burger svg { width: 18px; height: 18px; }

.scrim {
  display: none;
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, .6);
  z-index: 39;
}
.scrim.on { display: block; }

/* ── page furniture ───────────────────────────────────────────────── */
.crumb { font-size: 12.5px; color: var(--txt-3); margin-bottom: 8px; }
.crumb a { color: var(--txt-2); text-decoration: none; }
.crumb a:hover { text-decoration: underline; }

.head {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  gap: 12px; margin-bottom: 22px;
}
.head h1 {
  font-size: 26px; font-weight: 700; letter-spacing: -.02em;
  margin: 0; flex: 1 1 auto; min-width: 0;
}
.head .sub { font-size: 13.5px; color: var(--txt-2); margin: 4px 0 0; }
.head .acts { display: flex; gap: 8px; flex-wrap: wrap; }

.btn {
  border: 1px solid var(--edge-2);
  background: rgba(255, 255, 255, .05);
  color: var(--txt);
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.btn:hover { background: rgba(255, 255, 255, .1); }
.btn.pri { background: var(--otx-blue); border-color: var(--otx-blue); color: #FFFFFF; }
.btn.pri:hover { background: var(--otx-blue-lt); border-color: var(--otx-blue-lt); }
.btn.danger { color: #FF9B92; border-color: rgba(255, 155, 146, .35); }
.btn:disabled { opacity: .5; cursor: default; }
.btn.sm { padding: 5px 10px; font-size: 12.5px; border-radius: 6px; }

/* ── stat strip ───────────────────────────────────────────────────── */
.stats { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 22px; }
.stat {
  background: var(--panel); border: 1px solid var(--edge);
  border-radius: 9px; padding: 11px 15px; min-width: 96px;
}

/* A GRID on a phone, not a wrap. Four tiles at 390px wrapped 3 + 1, which left
   a lone "24 items" on its own row reading as a rendering fault rather than a
   number. Two by two is the same information and looks deliberate. */
@media (max-width: 560px) {
  .stats { display: grid; grid-template-columns: 1fr 1fr; }
  .stat { min-width: 0; }
}
.stat b {
  display: block; font-size: 22px; font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.stat span {
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-3);
}

/* ── cards and rows ───────────────────────────────────────────────── */
.card {
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 11px;
  overflow: hidden;
  margin-bottom: 18px;
}
.card-h {
  padding: 13px 17px;
  border-bottom: 1px solid var(--edge);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.card-h h2 { font-size: 14px; font-weight: 700; margin: 0; letter-spacing: -.005em; }
.card-h .grow { flex: 1; }

.row {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 17px;
  border-bottom: 1px solid var(--edge);
  text-decoration: none; color: inherit;
  width: 100%; background: none; border-left: none; border-right: none; border-top: none;
  text-align: left; cursor: pointer;
}
.row:last-child { border-bottom: none; }
.row:hover { background: rgba(255, 255, 255, .035); }
.row .body { flex: 1; min-width: 0; }
.row .what { font-size: 14.5px; font-weight: 600; }
.row .meta { font-size: 12.5px; color: var(--txt-3); margin-top: 2px; }
.row .chev { color: var(--txt-3); flex: none; }

/* THE TEAM'S BADGE IN A LIST ROW. It replaced a 4px bar of the brand colour,
   which told two teams apart only if you had memorised their hexes.

   A FIXED SQUARE, not stretch-to-row. The bar it replaced stretched to the row's
   height, so a row with two lines of meta made it taller than a row with one and
   a list of forty went ragged down its left edge. A badge is a badge at one size.

   The crest sits on the brand colour, contained rather than covering, because a
   wordmark and a roundel are not the same shape and cropping one to match the
   other is how you lose half a logo. A team with no crest keeps the colour, as a
   square rather than a sliver, so no row is missing its left edge. */
.tthumb {
  width: 34px; height: 34px; flex: none; align-self: flex-start;
  border-radius: 7px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  padding: 3px; box-sizing: border-box;
}
.tthumb img {
  display: block; max-width: 100%; max-height: 100%;
  width: auto; height: auto; object-fit: contain;
}

/* ── pills ────────────────────────────────────────────────────────── */
.pill {
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; padding: 4px 9px; border-radius: 5px;
  white-space: nowrap; flex: none;
}
.pill.idle  { background: rgba(255, 255, 255, .08); color: var(--txt-2); }
.pill.go    { background: var(--live-bg);            color: #97ACEF; }
.pill.wait  { background: rgba(224, 167, 75, .16);   color: #E0A74B; }
.pill.good  { background: rgba(76, 186, 132, .16);   color: #4CBA84; }
.pill.late  { background: rgba(241, 120, 109, .16);  color: #F1786D; }

/* THE FACTS STRIP. Short labelled cells across the top of a purchase order:
   who it goes to, when it is due, who it is for, how big it is. They were
   scattered between the subtitle, the form and the line list, so answering
   "what is this order" meant reading the whole screen. Sideline runs the same
   band above its PO details and it is the fastest part of that page to read. */
.pofacts { display: flex; flex-wrap: wrap; gap: 0; border: 1px solid var(--edge);
  border-radius: 10px; background: var(--panel); margin-bottom: 18px; overflow: hidden; }
.pofacts > div { flex: 1 1 150px; padding: 10px 14px; min-width: 0;
  border-right: 1px solid var(--edge); }
.pofacts > div:last-child { border-right: none; }
.pofacts b { display: block; font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--txt-3); margin-bottom: 3px; }
.pofacts span { font-size: 13px; font-weight: 600; }
.pofacts span.miss { color: #E0A74B; font-weight: 700; }
@media (max-width: 640px) { .pofacts > div { flex: 1 1 50%; } }

/* THE CONTROLS ON A LOGO ROW, which had no styling at all.
   .drop and the select rules are scoped to .grid, and a logo row is not inside
   one, so the Remove button and the reuse picker fell back to default browser
   chrome: a pale box on a dark panel, effectively invisible. True since the
   editor was written, and it is on the entry screen too. */
.logorow select, .logorow input[type=file] {
  background: var(--otx-black); border: 1px solid var(--edge); color: var(--txt-1);
  border-radius: 6px; padding: 6px 8px; font-size: 12.5px;
}
.logorow .drop {
  border: 1px solid var(--edge); background: none; color: var(--txt-3);
  cursor: pointer; padding: 5px 10px; border-radius: 6px; font-size: 12.5px;
}
.logorow .drop:hover { color: #F1786D; border-color: rgba(241, 120, 109, .45); }

/* LOGO ELEMENTS, collapsed. A kit carries a crest, a sponsor and the OTX2
   mark, and three six-field forms stacked open buried the size grid under
   eighteen inputs. Closed, a logo is one line that says what it is and where
   it goes; open, it is the same form it always was. */
.lgrow .lgsum { display: flex; gap: 10px; align-items: center; cursor: pointer;
  padding: 4px 0; }
.lgrow .lgthumb { width: 34px; height: 34px; object-fit: contain; background: #fff;
  border-radius: 5px; flex: none; }
.lgrow .lgtext { min-width: 0; }
.lgrow .lgname { font-size: 13px; font-weight: 600; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.lgrow .lgwhere { font-size: 11.5px; color: var(--txt-3); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.lgrow .lgchev { flex: none; opacity: .5; transition: transform .12s ease; }
.lgrow.open .lgchev { transform: rotate(90deg); }
.lgrow.open { background: rgba(255, 255, 255, .02); }

/* THE PRICE LIST, beside the box that overrides it. Sideline shows the
   supplier's own number next to the unit cost with a Use button, so an admin
   can see they have typed over it and snap back without going to look it up. */
.baseusd { font-size: 11px; color: var(--txt-3); display: flex; gap: 6px;
  align-items: center; }
.baseusd .btn { padding: 2px 8px; font-size: 11px; }

/* THE BUILD SCHEDULE. Seven milestone cards counted back from the due date.
   Romero's rule, 2026-04-16, written down in Sideline's shared/po-milestones.ts
   for the same factory: a 35 day cycle where day 1 is the design proof and day
   35 is the kit in hands. Not re-derived here, because a second copy of a
   production timeline that drifts from the first is worse than no copy. */
.sched { display: grid; gap: 8px; margin-bottom: 18px;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); }
.sched > div { border: 1px solid var(--edge); border-radius: 9px;
  background: var(--panel); padding: 9px 12px; }
.sched b { display: block; font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--txt-3); margin-bottom: 3px; }
.sched .what { font-size: 12.5px; font-weight: 600; line-height: 1.3; }
.sched .when { font-size: 11.5px; margin-top: 4px; font-variant-numeric: tabular-nums; }
/* DONE is a tick somebody made, and it outranks every other state. A stage
   done late is still done, and dimming it as "past" would hide the one fact
   the schedule now exists to record. */
.sched > div.done { opacity: .55; border-color: rgba(120, 200, 140, .35); }
.sched > div.done .what { text-decoration: line-through; }
.sched > div.done .when { color: var(--txt-3); }
.sched .by { font-size: 10.5px; color: var(--txt-3); margin-top: 3px; }
.sched > div .btn { margin-top: 8px; width: 100%; justify-content: center; }
/* Gone by and NOT ticked. This is the whole point of the rebuild: a date that
   passed with nothing recorded against it is late, and says so. */
.sched > div.past { opacity: .5; }
.sched > div.past .when { color: var(--txt-3); }
/* The one the order is standing on. */
.sched > div.now { border-color: var(--otx-blue); }
.sched > div.now .when { color: #97ACEF; font-weight: 700; }
/* Already behind, and nothing has been marked done. */
.sched > div.late { border-color: rgba(241, 120, 109, .5); opacity: 1; }
.sched > div.late .when { color: #F1786D; font-weight: 700; }

/* THE OUTWARD ACTION, coloured because it is the one that leaves the building.
   Every button on this screen looked identical, so emailing a factory in
   Sialkot sat beside "Print the sheet" with nothing to say which one somebody
   cannot take back. Sideline colours its dispatch buttons for the same
   reason. */
.btn.out { background: rgba(224, 167, 75, .14); border-color: rgba(224, 167, 75, .45);
  color: #E0A74B; }
.btn.out:hover { background: rgba(224, 167, 75, .22); }

/* ── forms ────────────────────────────────────────────────────────── */
.fields { display: grid; gap: 14px; padding: 17px; }
@media (min-width: 700px) { .fields.two { grid-template-columns: 1fr 1fr; } }
/* THREE ACROSS on a wide screen. A purchase order header is short labelled
   facts, not prose, and two columns of full-width inputs pushed the order
   itself below the fold on a laptop. */
@media (min-width: 980px) { .fields.three { grid-template-columns: 1fr 1fr 1fr; } }
.field label {
  display: block; font-size: 11.5px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--txt-3); margin-bottom: 6px;
}
.field input, .field select, .field textarea {
  width: 100%;
  background: var(--otx-black);
  border: 1px solid var(--edge-2);
  border-radius: 8px;
  padding: 9px 11px;
  font-size: 14.5px;
}
.field textarea { min-height: 86px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--otx-blue); outline-offset: 1px; border-color: transparent;
}
.field .hint { font-size: 12px; color: var(--txt-3); margin-top: 5px; }

.check { display: flex; align-items: flex-start; gap: 10px; padding: 9px 17px; cursor: pointer; }
.check input { width: 17px; height: 17px; margin: 2px 0 0; flex: none; accent-color: var(--otx-blue); }
.check .what { font-size: 14px; font-weight: 600; }
.check .meta { font-size: 12px; color: var(--txt-3); }

/* ── notices ──────────────────────────────────────────────────────── */
.note {
  display: none;
  border-radius: 9px; padding: 11px 14px; margin-bottom: 16px; font-size: 14px;
  border: 1px solid var(--edge-2); background: var(--panel-2);
}
.note.on { display: block; }
.note.bad { border-color: rgba(241, 120, 109, .4); background: rgba(241, 120, 109, .1); color: #F1786D; }
.note.good { border-color: rgba(76, 186, 132, .4); background: rgba(76, 186, 132, .1); color: #4CBA84; }
/* Amber, not red. A placeholder price is not an error, it is a number that is
   counted in a total and has not been confirmed yet, and it stops being read
   the moment it looks like the failures beside it. */
.note.warn { border-color: rgba(224, 168, 78, .45); background: rgba(224, 168, 78, .12); color: #E0A84E; }

.empty { padding: 34px 20px; text-align: center; color: var(--txt-3); font-size: 14px; }

/* A heading INSIDE a card, for a card that holds two lists. The cost card runs
   garments and then squads, and without a divider the second list reads as more
   of the first. Not an h2: the card already has one, and a second would say this
   is a second card. */
.sub-h {
  padding: 14px 17px 6px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--txt-3); border-bottom: 1px solid var(--edge);
}

/* A row that ends in money. Not clickable, unlike every other .row, so the
   pointer and the hover come off: a row that lights up under the cursor and then
   does nothing when clicked is a promise the screen does not keep. Digits are
   tabular so a column of totals lines up on the decimal. */
.costrow { cursor: default; }
.costrow:hover { background: none; }
.costrow > b { font-size: 14px; font-variant-numeric: tabular-nums; flex: none; }

/* A link handed to a person: monospaced, selectable, never truncated to
   something that looks complete but is not. */
.link-out {
  font-family: var(--otx-mono); font-size: 12.5px;
  background: var(--otx-black); border: 1px solid var(--edge-2);
  border-radius: 8px; padding: 10px 12px; word-break: break-all;
  user-select: all; margin: 0 17px 14px;
}

/* ── tables ───────────────────────────────────────────────────────── */
.scroll { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: 13.5px; }
th, td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--edge); }
th {
  font-size: 10.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--txt-3); white-space: nowrap; background: var(--panel-2);
}
tr:last-child td { border-bottom: none; }
td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mono { font-family: var(--otx-mono); font-size: 12.5px; }

/* ── the capture grid ─────────────────────────────────────────────── */
.grid-wrap { overflow-x: auto; }
.grid { border-collapse: separate; border-spacing: 0; min-width: 560px; width: 100%; }
.grid th, .grid td { padding: 7px 9px; border-bottom: 1px solid var(--edge); }
.grid th:first-child, .grid td:first-child { position: sticky; left: 0; background: var(--panel); z-index: 1; }
.grid th { background: var(--panel-2); }
.grid input, .grid select {
  width: 100%; min-width: 74px;
  background: var(--otx-black); border: 1px solid var(--edge);
  border-radius: 6px; padding: 6px 8px; font-size: 13.5px;
}
.grid .no { width: 62px; min-width: 62px; }
.grid .drop { border: none; background: none; color: var(--txt-3); cursor: pointer; padding: 4px 7px; }
.grid .drop:hover { color: #F1786D; }

/* ── the phone ────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .rail {
    transform: translateX(-100%);
    transition: transform .18s ease;
    box-shadow: 0 0 40px rgba(0, 0, 0, .6);
  }
  .rail.open { transform: translateX(0); }
  .main { margin-left: 0; }
  .main-in { padding: 18px 14px 70px; }
  .topbar { display: flex; }
  .head h1 { font-size: 22px; }
}

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

:focus-visible { outline: 2px solid var(--otx-blue); outline-offset: 2px; }

/* ── the purchase order sheet ─────────────────────────────────────────
   A DOCUMENT, not an admin screen. It gets saved as a PDF and emailed to
   Sialkot, so it drops the dark chrome entirely and is set in the same black
   bands and hairline panels as the design proof the factory already reads.

   Scoped to .sheet-mode on the body so nothing here can leak into the admin;
   paint() removes the class on every route that is not the sheet. */
body.sheet-mode { background: #fff; color: #000; }
body.sheet-mode .rail,
body.sheet-mode .topbar,
body.sheet-mode .scrim { display: none !important; }
body.sheet-mode .main { margin-left: 0; }
body.sheet-mode .main-in { max-width: 900px; margin: 0 auto; padding: 32px 40px 80px; }

.sheet { font-size: 12px; line-height: 1.5; color: #000; }
.sheet-bar { display: flex; gap: 8px; margin-bottom: 20px; }
.sheet-bar .btn { border-color: #bbb; background: #fff; color: #000; }
.sheet-bar .btn.pri { background: #000; border-color: #000; color: #fff; }

.sheet-head {
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  border-bottom: 2px solid #000; padding-bottom: 12px; margin-bottom: 18px;
}
.sheet-head h1 { font-size: 19px; margin: 0; letter-spacing: .06em; }
.sheet-head .ref { font-family: var(--otx-mono); font-size: 15px; margin-top: 4px; }
.sheet-meta { display: grid; gap: 3px; font-size: 11.5px; }
.sheet-meta div { display: flex; gap: 8px; align-items: baseline; }
/* Filled value cells against bold labels. It is the single strongest detail on
   Sideline's header and it is what makes the two documents read as the same
   kind of paper. */
.sheet-meta span { background: #f2f2f2; padding: 3px 9px; min-width: 180px; }
/* Dates and references column-align, which is the whole point of a mono face
   on a document somebody files by reference. */
.sheet-meta span { font-family: var(--otx-mono); font-size: 11px; }
.sheet-meta b { min-width: 52px; text-transform: uppercase; font-size: 10px;
  letter-spacing: .08em; color: #555; align-self: center; }

/* The filter row above the purchase order list. */
.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  padding: 13px 17px; }
.filters input { flex: 1; min-width: 190px; }

/* NOT break-inside:avoid on every block. A garment block is a bar, a spec line,
   a size table, a price line, a mockup strip and a placement grid; that exceeds
   an A4 page, and Chrome answers an impossible avoid by breaking wherever it
   likes. The short blocks keep it, the tall ones delegate to the finer rules on
   rows, figures and the grid. */
.sheet-block { margin-bottom: 20px; }
.sheet-block.keep { break-inside: avoid; }
table.lp { break-inside: avoid; }
.sheet-block h2 {
  font-size: 12px; letter-spacing: .03em; text-transform: uppercase;
  background: #000; color: #fff; padding: 6px 16px; margin: 0 0 8px;
  /* A black bar stranded at the foot of a page is a chapter heading with no
     chapter under it. */
  break-after: avoid;
}
/* A garment opens a chapter; the blocks inside it sit one level down. Without
   two weights the sheet reads as a flat list where "Deliver to" and "Tag
   Shorts" carry identical importance. */
/* FIRST child only. The sizing guide and the placement grid are bars inside
   the chapter, not chapters of their own, and giving them the heavier weight
   flattens the hierarchy this rule exists to create. */
.sheet-block.garment > h2:first-child { font-size: 13px; padding: 8px 16px; }
.sheet-block p { margin: 0 0 6px; }
.sheet .spec { font-size: 11px; color: #444; }

/* WHAT THE FACTORY MUST NOT READ PAST. Same red the missing-mockup notice
   already uses, rather than a second one, so the sheet has exactly one colour
   that means "stop". */
.sheet .alarm { color: #9B1226; font-weight: 700; }

/* The letterhead above the purchase order title. */
.sheet-letter { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 18px; }
/* ON A DARK BADGE, because the mark is white and this document is white paper.
   Printed straight it is an invisible smudge in the corner of a page going to
   Sialkot. Same treatment, same navy, as the coach's proof sheet header, so the
   two documents read as coming from the same company. print-color-adjust keeps
   the badge when the browser would otherwise drop backgrounds for printing. */
.sheet-letter .badge { background: #01123E; border-radius: 5px; padding: 8px 12px;
  display: inline-block; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.sheet-letter .badge img { height: 26px; width: auto; display: block; }

/* STATUS / APPROVED BY / DATE / REFERENCE, high in the document where
   Sideline puts its artwork-approval band, because whether a thing is signed
   off is the first question a factory has and the last thing it should have to
   hunt for. */
/* Hairlines at #eee, the same language as every other rule on the page, and no
   top border because the black bar above supplies it. */
.sheet-band { display: flex; gap: 0; border: 1px solid #eee; border-top: none;
  margin: -8px 0 20px; }
.sheet-band div { flex: 1; padding: 10px 14px; border-right: 1px solid #eee; }
.sheet-band div:last-child { flex: 1.3; }
.sheet-band .ref, .sheet-band .when { font-family: var(--otx-mono); }
/* STATUS reads as a state, not as another value. */
.sheet-band .chip { display: inline-block; padding: 3px 10px; border-radius: 3px;
  color: #fff; font-weight: 700; font-size: 10px; letter-spacing: .03em; }
.sheet-band .chip.go   { background: #16a34a; }
.sheet-band .chip.wait { background: #F59E0B; }
/* OTX2 has a third state Sideline does not: nothing to approve. */
.sheet-band .chip.none { background: #5A6270; }
.sheet-band div:last-child { border-right: 0; }
.sheet-band b { display: block; font-size: 9px; letter-spacing: .08em;
  text-transform: uppercase; color: #555; margin-bottom: 3px; }
.sheet-band span { font-size: 11.5px; font-weight: 700; }

/* THE SIZING GUIDE. The measurements already exist in /charts.js, verified
   against each garment's own run, and until now only the coach's screen and the
   proof sheet could see them. A factory sheet that says "make 18 singlets, one
   of each size" without saying what a size measures is asking Sialkot to use
   its own block. */
table.sizes { width: 100%; border-collapse: collapse; margin: 6px 0 10px;
  font-size: 10px; }
table.sizes th, table.sizes td { border: 1px solid #ddd; padding: 3px 6px;
  text-align: center; font-variant-numeric: tabular-nums; }
/* colour EXPLICITLY. The admin's global th rule paints headings in the dark
   theme's light ink, which on a pale blue band is invisible, and an
   unreadable size chart on a factory sheet is worse than no chart. */
table.sizes th { background: #c9d9ea; font-weight: 700; color: #000; }
table.sizes td:first-child, table.sizes th:first-child { text-align: left;
  white-space: nowrap; }
.sizes-foot { display: flex; justify-content: space-between; font-size: 9px;
  color: #666; margin: -4px 0 10px; }
.sizes-note { font-size: 9.5px; color: #9B1226; margin: -4px 0 10px; }

table.sheet-table { width: 100%; border-collapse: collapse; margin: 8px 0; font-size: 11px; }
.sheet-table th, .sheet-table td {
  border: 1px solid #ccc; padding: 4px 6px; text-align: center;
  font-variant-numeric: tabular-nums;
}
/* Colour stated OUTRIGHT, not inherited. The admin's global th is a pale grey
   for a dark panel; on the sheet's white ground that renders the size headers
   all but invisible, which was exactly what the first print showed. Anything on
   this document that sets a colour states it, because the document does not
   live in the dark theme the rest of this file describes. */
.sheet-table th { background: #eee; font-weight: 700; color: #000; }
.sheet-table th:first-child, .sheet-table td:first-child { text-align: left; white-space: nowrap; }
.sheet-table tr.make td { background: #f2f2f2; font-weight: 700; }

.sheet-total {
  display: flex; gap: 24px; border-top: 2px solid #000; border-bottom: 2px solid #000;
  padding: 10px 0; margin: 18px 0 10px;
}
.sheet-total div { display: flex; align-items: baseline; gap: 7px; }
.sheet-total b { font-size: 17px; font-variant-numeric: tabular-nums; }
.sheet-total span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; color: #555; }

/* ── the renders on the order sheet ───────────────────────────────────
   Sideline's purchase orders carry a vendor render under every garment, and
   Puffin read those. Same idea here.

   The images are on a WHITE panel and are never cropped. object-fit: contain
   rather than cover, because a cover crop on a kit render cuts the sleeve or
   the number off, and the whole reason the picture is on the page is so the
   factory can see the detail. */
.mock { margin: 10px 0 4px; }
.mock-group { margin-bottom: 12px; break-inside: avoid; }
.mock-who {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: #000; padding-bottom: 5px; border-bottom: 1px solid #bbb; margin-bottom: 8px;
}
.mock-strip { display: flex; flex-wrap: wrap; gap: 10px; }
.mock-fig {
  margin: 0; flex: 1 1 210px; max-width: 320px; break-inside: avoid;
  border: 1px solid #ccc; border-radius: 4px; overflow: hidden; background: #fff;
}
.mock-fig img { display: block; width: 100%; height: 160px; object-fit: contain; background: #fff; }
.mock-fig figcaption {
  font-size: 10px; color: #333; padding: 5px 7px; border-top: 1px solid #e2e2e2;
  background: #fafafa; line-height: 1.35;
}
.mock-gone {
  height: 160px; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 10px; font-size: 10.5px; color: #9B1226;
  background: #FBE4E7;
}

@media print {
  /* A4, and nothing on the page that cannot be posted. */
  /* 10mm, matching Sideline. The size grids here are wide — a garment on the
     default run is 13 columns — and 14mm was costing 8mm of usable width. */
  @page { size: A4; margin: 10mm; }
  body.sheet-mode .main-in { padding: 0; max-width: none; }
  .no-print { display: none !important; }
  .sheet-block { break-inside: avoid; }
  .sheet-table { break-inside: auto; }
  .sheet-table tr { break-inside: avoid; }
  /* Print the renders. A browser drops background images by default and would
     drop these too without it, which would post the factory a sheet of empty
     boxes. */
  .mock-fig, .mock-group { break-inside: avoid; }
  .mock-fig img { height: 130px; }
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ── the per-team production sheet ────────────────────────────────────
   Sideline's order page, which is the pattern Romero already reads: one page
   per thing being made, a tab strip across the top, a wide left column and a
   narrow summary rail, and a stage pipeline showing where it is up to. The
   difference here is the shareable link, which OTX2 needs and Sideline does
   not, so it gets its own tab rather than being tucked into a corner. */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--edge-2); margin-bottom: 20px; }
.tabs button {
  padding: 10px 18px; font: inherit; font-size: 13px; font-weight: 500;
  background: none; border: none; color: var(--txt-3); cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabs button:hover { color: var(--txt); }
.tabs button.on { color: var(--txt); border-bottom-color: var(--txt); }

.split { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 20px; align-items: start; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; } }

/* The pipeline. Numbered, because "where is it up to" is a question about
   ORDER, and a row of icons with no numbers makes people count. */
.stages { display: flex; flex-direction: column; gap: 0; }
.stage { display: flex; gap: 12px; align-items: flex-start; padding: 0 0 2px; }
.stage-mark { display: flex; flex-direction: column; align-items: center; align-self: stretch; }
.stage-dot {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 11.5px; font-weight: 700;
  border: 1.5px solid var(--edge-2); color: var(--txt-3); background: var(--panel-2);
}
.stage-line { width: 1.5px; flex: 1; min-height: 14px; background: var(--edge-2); }
.stage.done .stage-dot { background: #4CBA84; border-color: #4CBA84; color: #06210f; }
.stage.done .stage-line { background: #4CBA84; }
.stage.now .stage-dot { background: #E0A84E; border-color: #E0A84E; color: #241800; }
.stage-body { padding-bottom: 14px; min-width: 0; }
.stage-what { font-size: 13.5px; color: var(--txt-2); }
.stage.done .stage-what, .stage.now .stage-what { color: var(--txt); font-weight: 600; }
.stage-when { font-size: 11.5px; color: var(--txt-3); margin-top: 2px; }

/* The summary rail. Label left, value right, one line each. */
.facts { display: flex; flex-direction: column; gap: 10px; font-size: 13px; }
.facts > div { display: flex; justify-content: space-between; gap: 12px; }
.facts .k { color: var(--txt-3); }
.facts .v { color: var(--txt); text-align: right; }
.facts .rule { border-top: 1px solid var(--edge-2); padding-top: 10px; margin-top: 2px; }

/* ── the board, by contingent ──────────────────────────────────────
   THE SAME BLOCK VOCABULARY THE COACH SEES. filled = signed off,
   hatched = waiting on a signature, dotted = not there yet. The shapes
   carry the meaning and are identical on both screens; only the palette
   follows the surface, because this one is dark and the coach's is not.
   A phone call about a contingent is then two people reading one language. */
.blocks { display: inline-flex; flex-wrap: wrap; gap: 4px; align-items: center; flex: none; }
.blk { width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--edge-2); }
.blk.filled  { background: #4CBA84; border-color: #4CBA84; }
.blk.hatched { background: repeating-linear-gradient(45deg,
                 #E0A84E 0 2px, transparent 2px 4px); border-color: #E0A84E; }
.blk.dotted  { background: none; border-style: dotted; }

.board-overview { padding: 14px 16px; border-bottom: 1px solid var(--edge); }
.board-overview .ov-h { font-size: 13px; color: var(--txt-2); margin-bottom: 10px; }
.board-overview .ov-h b { color: var(--txt); font-size: 14px; }
/* Five clusters of six, separated, so the shape of the event is readable
   without counting: a gap is a contingent boundary. */
.ov-blocks { display: flex; flex-wrap: wrap; gap: 16px; }

/* The two states that cut across contingents. Flat and ungrouped, because
   they are the only reasons to do something today. */
.chase { padding: 10px 16px; border-bottom: 1px solid var(--edge); font-size: 13px; }
.chase b { color: #E0A84E; margin-right: 8px; }
.chase-list { color: var(--txt-2); }

details.cgroup { border-bottom: 1px solid var(--edge); }
details.cgroup > summary {
  display: flex; align-items: center; gap: 12px; padding: 12px 16px;
  cursor: pointer; list-style: none;
}
details.cgroup > summary::-webkit-details-marker { display: none; }
details.cgroup > summary::after {
  content: "\203A"; color: var(--txt-3); font-size: 18px; line-height: 1;
  transform: rotate(90deg); transition: transform .12s;
}
details.cgroup[open] > summary::after { transform: rotate(-90deg); }
details.cgroup > summary:hover { background: var(--panel-2); }
details.cgroup > summary .body { flex: 1; min-width: 0; }
details.cgroup > summary .what { font-size: 14.5px; font-weight: 650; }
details.cgroup > summary .meta { font-size: 12px; color: var(--txt-3); margin-top: 2px; }
/* An expanded group's rows sit inside it, indented past the badge column so the
   contingent reads as the parent of its squads. The number tracks .tthumb's
   width plus .row's own padding and gap: 17 + 34 + 12. It was 34 when the badge
   was a 4px stripe, and a squad list that no longer lines up under its
   contingent is the first thing this indent exists to prevent. */
details.cgroup > .row { padding-left: 63px; }

/* The spec sheet: Sideline's placement matrix, in OTX2's skin.
   Rows are what is applied and how, columns are where it goes. The logo
   itself is the first row because that is the one somebody actually checks:
   a name in a cell does not tell you the crest is the right season's. */
table.grid.spec th { white-space: nowrap; font-size: 10px; }
table.grid.spec td.nm {
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; color: var(--txt-3);
  white-space: nowrap; vertical-align: middle;
}
table.grid.spec td.g { text-align: center; vertical-align: middle; min-width: 120px; }
.spec-logo {
  display: block; margin: 0 auto 6px; max-width: 88px; max-height: 56px;
  object-fit: contain; background: #fff; border-radius: 6px; padding: 5px;
}
.spec-name { font-size: 11.5px; color: var(--txt-2); line-height: 1.35; }
/* A dash where Sideline holds nothing. Dimmed so a row of them reads as
   "not filled in over there", not as a broken table. */
table.grid.spec td.spec-gap { color: var(--txt-3); }

/* The placement grid on the printable purchase order. Same vocabulary as the
   shared sheet and the coach's ledger: the factory and the customer are
   reading one document in two audiences, not two documents. */
.sheet table.lp { border-collapse: collapse; width: 100%; margin: 10px 0 4px; }
/* COLOURS SET EXPLICITLY, not inherited. The admin is a dark theme and .sheet
   is a light print surface: without these the table inherited near-white text
   onto #f2f2f2 and the column headers rendered invisible. Found by reading the
   computed style off the rendered page, not by looking at the markup. */
.sheet table.lp th, .sheet table.lp td {
  border: 1px solid #ccc; padding: 5px 5px; font-size: 10px; text-align: center;
  vertical-align: middle; color: #000; background: #fff;
}
.sheet table.lp th { background: #f2f2f2; color: #333; font-size: 8.5px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; white-space: nowrap; }
.sheet table.lp td.lbl, .sheet table.lp th.lbl {
  text-align: left; font-size: 8.5px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; white-space: nowrap; background: #fff; color: #333;
}
.sheet table.lp img { display: block; margin: 0 auto 3px; max-width: 54px; max-height: 34px; object-fit: contain; }
.sheet table.lp .nm { font-size: 8.5px; line-height: 1.25; color: #000; }
.sheet table.lp .dash { color: #aaa; }

/* The pinned event at the top of the rail. It is the job, so it reads as a
   heading rather than as one more link in a list of nine. */
.nav-i.nav-ev { font-weight: 700; }
.nav-rule { border-top: 1px solid var(--edge); margin: 10px 12px; }

/* ── event, contingent, team ─────────────────────────────────────────
   Romero, 2026-08-21: "simple list under each comp team contingent easily sub
   indented to follow", then 2026-08-22: "fix formating of the view especially
   for mobile view".

   The first version was a flex row, and on a phone it fell apart completely:
   the actions would not shrink, so the text column collapsed to almost nothing,
   and overflow-wrap: anywhere then broke the contingent's URL ONE CHARACTER PER
   LINE. A heading came out 1415px tall and the buttons sat off the right edge
   where nothing could reach them.

   So it is a GRID now, which is the difference that matters: a grid track can
   be told its size, where a flex item is only ever asked politely. Text takes
   1fr with min-width 0, the buttons take their own track, and on a narrow
   screen the whole thing becomes one column and the buttons get a full-width
   row of their own.

   AND THE URL IS ONE ELLIPSISED LINE, at every width. A sixty character token
   printed in full is not something anybody reads: it is something they copy,
   and there are two buttons beside it that do exactly that. Showing all of it
   cost a screen and a half of scrolling per contingent and bought nothing. */
.tree-c {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 10px;
  align-items: start;
  padding: 14px 16px 10px;
  border-top: 1px solid var(--edge);
}
.tree-c:first-of-type { border-top: none; }

.tree-c .tree-head { min-width: 0; }
.tree-c .tree-name { font-size: 15px; font-weight: 700; line-height: 1.25; }
/* nowrap + ellipsis, and min-width 0 on the track above, are what stop a URL
   from being able to set this row's height at all. */
.tree-c .tree-link {
  font-size: 11.5px; color: var(--txt-3); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tree-c .tree-count {
  grid-column: 2; justify-self: end; flex: none;
  font-size: 12px; color: var(--txt-3); white-space: nowrap; padding-top: 3px;
}
/* Full width, below the name, and wrapping. Three buttons never fit beside a
   contingent name on a 360px screen and pretending otherwise is what put them
   off the edge. */
.tree-c .tree-acts {
  grid-column: 1 / -1;
  display: flex; gap: 6px; flex-wrap: wrap; margin-top: 9px;
}
.tree-c .tree-acts .btn { flex: 0 1 auto; }

/* The team line. Indented by a rule rather than by padding alone, because
   padding stops reading as a hierarchy the moment a name wraps. */
/* Three tracks on a wide screen: the team, its state, and the way in. Two
   auto tracks rather than one, or the pill and the button share a column and
   stack on top of each other where there is plenty of room for both. */
.tree-t {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 2px 10px;
  align-items: center;
  margin-left: 16px; padding: 11px 16px 11px 14px;
  border-left: 2px solid var(--edge);
}
.tree-t + .tree-c { margin-top: 6px; }
.tree-t .body { min-width: 0; }
.tree-t .what { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.tree-t .meta { font-size: 12.5px; color: var(--txt-3); margin-top: 2px; }
.tree-t .pill { grid-column: 2; justify-self: end; flex: none; }
.tree-t .btn  { grid-column: 3; justify-self: end; flex: none; }
.tree-empty { font-size: 12.5px; color: var(--txt-3); }

/* Narrow: one column throughout, and everything that was pinned right comes
   back to the left under what it belongs to. */
/* ── the admin on a phone ──────────────────────────────────────────
   Not modelled on Sideline: its order screen has no mobile handling at all,
   no responsive classes, no wrapping, no overflow rails, and fixed pixel
   widths up to 220px. Copying that would be a regression. These rules exist
   because the purchase order screen is genuinely used standing up at a field.
*/
@media (max-width: 640px) {
  /* THE LOGO ROW. A file input, a reuse picker, a delete and a remove on one
     wrapped line gives every control about 80px, and a <select> at 80px shows
     no logo name at all, which is the only thing that makes it pickable. Each
     control takes the full width and stays legible. */
  .logorow { gap: 8px; }
  .logorow > * { flex: 1 1 100%; min-width: 0; max-width: none; }
  /* !important because both carry an inline max-width from the editor, and an
     inline style beats a stylesheet rule without it. */
  .logorow select { max-width: none !important; width: 100%; }
  .logorow input[type=file] { max-width: none !important; width: 100%; }
  /* The thumbnail and the two buttons still sit together: they are glanceable
     rather than readable, so they do not need the width. */
  .logorow img { flex: 0 0 auto; }
  .logorow .grow { display: none; }

  /* THE SIZE RUN. Fixed 64px boxes with a label above wrap into ragged rows.
     A grid keeps them in even columns, and a size run of eighteen stays
     countable instead of becoming a wall. */
  .runrow { display: grid !important;
    grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); align-items: end; }
  .runrow input { width: 100% !important; }
  /* The buttons at the end of the run span the full width rather than being
     squeezed into one 74px cell. */
  .runrow .btn { grid-column: 1 / -1; }

  /* NOT touching .stats. There is already a deliberate rule at 560px making it
     two by two, with the reasoning written beside it: a lone tile on its own
     row reads as a rendering fault rather than a number. Leave it. */

  /* TAP TARGETS. Everything on this screen is sized for a mouse: inputs and
     small buttons land around 28px, which is under any reasonable thumb. This
     is a purchase order screen that gets used standing up at a field. */
  .main input, .main select, .main textarea, .main .btn {
    min-height: 40px;
  }
  .main .btn.sm { min-height: 36px; }
}

@media (max-width: 640px) {
  .tree-c, .tree-t { grid-template-columns: minmax(0, 1fr); }
  .tree-c .tree-count { grid-column: 1; justify-self: start; padding-top: 4px; }
  .tree-t .pill, .tree-t .btn { grid-column: 1; justify-self: start; }
  .tree-t .btn { margin-top: 9px; }
  .tree-t { padding: 12px 14px 13px 14px; }

  /* THUMBS, NOT CURSORS. .btn.sm is 27px tall, which is fine beside a mouse
     and is below every touch-target guideline there is. Raised here only, so
     the rest of the admin's small buttons are left as they are. */
  .tree-c .btn, .tree-t .btn {
    min-height: 44px; padding: 11px 16px; font-size: 13.5px; border-radius: 8px;
  }
}

/* The email of whoever entered the team, under its name. Its own line because
   an address is one long unbreakable token and must not be able to widen the
   row; selectable because the point of showing it is to copy it. */
.tree-t .tree-mail {
  overflow-wrap: anywhere; user-select: text; margin-top: 1px;
}

/* The contingent's delivery address on its heading. One line, ellipsised like
   the link above it: it is here to be checked at a glance, and the full thing
   is on every one of that contingent's proof sheets. */
.tree-c .tree-ship {
  font-size: 11.5px; color: var(--txt-3); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── the colour palette ─────────────────────────────────────────────
   Two renderers, one vocabulary. .cols is the editor on the purchase
   order screen; .pal is the read-only band that prints on the sheet the
   factory reads. A swatch with no hex behind it is drawn as a crossed
   box rather than as white, because an empty square on a printed page
   reads as "white" and white is a colour somebody will dye to. */
.cols .colrow { display: flex; gap: 7px; align-items: center; margin-bottom: 6px;
  flex-wrap: wrap; }
.cols .colsw { width: 30px; height: 22px; border-radius: 3px; flex: none;
  border: 1px solid var(--edge); }
.cols .colsw.none, .sheet .palsw.none {
  background-image: linear-gradient(45deg, transparent 45%, #c33 45%, #c33 55%,
    transparent 55%); background-color: transparent; }
.cols .colpick { width: 34px; height: 26px; padding: 0; flex: none; }
.cols .colname { width: 130px; }
.cols .colhex  { width: 96px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.cols .colpms  { width: 150px; }
.cols .colnone { font-size: 12.5px; color: var(--txt-3); padding: 3px 0 5px; }

.sheet .pal { display: flex; flex-wrap: wrap; gap: 16px; margin: 4px 0 12px; }
.sheet .palc { display: flex; align-items: center; gap: 8px; font-size: 11.5px; }
.sheet .palsw { width: 30px; height: 18px; border: 1px solid #bbb; border-radius: 2px;
  display: inline-block; flex: none; }
.sheet .palc b { font-weight: 700; }
.sheet .palhex { color: #777; margin-left: 5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.sheet .palpms { font-weight: 700; color: #8a6d1f; margin-left: 6px; }

@media (max-width: 640px) {
  .cols .colname, .cols .colhex, .cols .colpms { width: 100%; }
}

/* ── accordions ─────────────────────────────────────────────────────
   Native details/summary, so they work with JavaScript half-loaded, are
   keyboard operable and screen-reader labelled without any of that being
   re-implemented, and stay findable by Ctrl-F where the browser supports
   hidden=until-found.

   .gsec is one garment on a purchase order; .fold is a whole card that has
   been converted by foldCard(). Both wear the same chevron and the same
   summary styling as the .card-h they replaced, so folding a section does
   not change what it looks like when open. */
.gsec { border-top: 1px solid var(--edge); }
.card > .gsec:first-of-type { border-top: 0; }
.gsec > summary { cursor: pointer; list-style: none; user-select: none; }
.gsec > summary::-webkit-details-marker { display: none; }
.gsec > summary::after {
  content: ""; width: 8px; height: 8px; flex: none; margin-left: 10px;
  border-right: 2px solid var(--txt-3); border-bottom: 2px solid var(--txt-3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .12s ease;
}
.gsec[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.gsec > summary:hover { background: var(--row-hover, rgba(255,255,255,.03)); }
.gsec > summary:focus-visible { outline: 2px solid var(--accent, #4d8dff); outline-offset: -2px; }
.card.fold { display: block; }

/* A COLLAPSED SECTION ON A PRINTED PURCHASE ORDER IS A SECTION THE FACTORY
   NEVER SEES. Everything opens for print, and the chevron goes, because it is
   a control and there are no controls on paper. */
@media print {
  .gsec > summary::after { display: none; }
  .gsec > summary { cursor: auto; }
}

/* ── text inputs, so they are actually readable ──────────────────────
   `button, input, select, textarea { color: inherit }` at the top of this
   file is right for buttons and wrong for text boxes. An input inside a
   label styled `color: var(--txt-3)` inherited near-white text, and no rule
   gave a bare input a background, so the browser painted its default WHITE
   box behind it. The result was invisible text in a visible box.

   It was not theoretical: the Material / spec field on every garment line of
   every purchase order was blank to look at while holding "150gsm Interlock
   Polyester (double-layer reversible), sublimated", so an admin checking what
   the factory had been told saw an empty field and had no way to know
   otherwise. Only the inputs inside .grid and .field were ever styled, and
   those two were the only ones anybody had looked at.

   Scoped to .main so the sign-in screen and anything outside the admin shell
   keep their own treatment, and every control that is NOT a text box is left
   alone: a checkbox, a radio, a colour well and a file button all draw
   themselves and painting a background over them breaks them. */
.main input:not([type=checkbox]):not([type=radio]):not([type=color]):not([type=file]),
.main select,
.main textarea {
  background: var(--otx-black);
  color: var(--txt);
  border: 1px solid var(--edge);
  border-radius: 6px;
  padding: 6px 8px;
  font-size: 13.5px;
}
.main input::placeholder, .main textarea::placeholder { color: var(--txt-3); }
.main input:focus-visible, .main select:focus-visible, .main textarea:focus-visible {
  outline: 2px solid var(--live); outline-offset: -1px; border-color: transparent;
}
/* The material line is a sentence, not a size box, and 116px of it was four
   words of a fabric spec. */
.gsec input.specline { width: 100%; max-width: 520px; }

/* An anchor wearing .btn. The Drive link has to be a real <a> so it opens in a
   new tab and can be middle-clicked and copied, and a bare anchor inherits the
   link colour and the underline from `a { color: var(--live) }`. */
a.btn { display: inline-flex; align-items: center; gap: 5px; text-decoration: none;
  color: var(--txt); }
a.btn:hover { text-decoration: none; }

/* THE CHASE CARD, opened in place under the person it belongs to. Only ever one
   is open at a time, which is the whole point of the screen: one send armed, one
   decision in front of you. */
.chase-card { padding: 4px 17px 16px; border-bottom: 1px solid var(--edge); }
.chase-card:last-child { border-bottom: none; }

/* The words that will actually go, shown whole. Wrapped rather than scrolled
   sideways, because an email nobody can read all of is an email nobody has
   approved. */
.chase-body {
  font-family: var(--otx-mono); font-size: 12px; line-height: 1.55;
  white-space: pre-wrap; word-break: break-word;
  background: var(--otx-black); border: 1px solid var(--edge-2);
  border-radius: 8px; padding: 12px 14px; margin: 0 0 12px;
  max-height: 340px; overflow-y: auto;
}


/* EXTRA GEAR, AS A CHECKOUT LIST.
 *
 * Romero, 2 September 2026: "ADD THE PRODUCT THUMBNAIL LIKE MAKE IT LOOK LIKE A
 * CHECKOUT LIST VIEW". The first version was a stack of run tables, which is
 * how a factory counts and the wrong shape for the question this screen asks,
 * which is what did this team buy. One row per product: the picture, the name,
 * the sizes as chips, the count on the right.
 *
 * Grid rather than flex so the three columns line up down the list however long
 * a garment's name runs. */
.xrow {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 12px 17px;
  border-top: 1px solid var(--edge);
}
.xthumb {
  width: 56px; height: 56px;
  object-fit: contain;
  background: rgba(128, 128, 128, .10);
  border-radius: 8px;
}
/* A garment whose mockup has not been loaded yet, so the row keeps its shape
   rather than collapsing or showing a broken image. */
.xthumb-none {
  display: flex; align-items: center; justify-content: center;
  color: var(--txt-3); font-size: 18px;
}
.xbody { min-width: 0; }
.xname { font-weight: 600; font-size: 14px; }
.xsizes { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
/* One chip per size actually ordered. tabular-nums so the counts line up when
   several chips sit side by side. */
.xchip {
  display: inline-flex; gap: 5px; align-items: baseline;
  border: 1px solid var(--edge); border-radius: 999px;
  padding: 2px 9px; font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.xchip b { font-weight: 650; }
.xchip span { color: var(--txt-3); }
.xqty { text-align: right; white-space: nowrap; }
.xqty b { display: block; font-size: 18px; font-variant-numeric: tabular-nums; }
.xqty span { font-size: 11.5px; color: var(--txt-3); }
.xmoney { display: block; margin-top: 2px; }
.xfoot { padding: 13px 17px; border-top: 1px solid var(--edge); }
.xfoot .meta { font-size: 12px; color: var(--txt-3); margin-top: 3px; }


/* WHAT A SQUAD IS WAITING ON, under its name.
 *
 * Romero, 2 September 2026: "we should have flag notifications for missing
 * items / actions needed asweel listed underneath each team name so that we can
 * filter by action stage etc per contigent."
 *
 * Toned by STAGE rather than by severity, because the question is what to do
 * and not how bad it is: a chase is somebody to ring, a fix is OTX2's own to
 * make, a signature is waiting on a person, and a wait is out of everyone's
 * hands here. Four tones so a glance down the board sorts itself. */
.flags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.flag {
  display: inline-block;
  font-size: 11.5px; line-height: 1.5;
  padding: 1px 8px; border-radius: 999px;
  border: 1px solid transparent;
}
/* Somebody has to be rung. The loudest, because it is the only kind that does
   not get better on its own. */
.flag-chase { color: #F1786D; border-color: rgba(241, 120, 109, .38);
  background: rgba(241, 120, 109, .10); }
/* OTX2 can put this right without anybody else. */
.flag-fix   { color: #E3B341; border-color: rgba(227, 179, 65, .38);
  background: rgba(227, 179, 65, .10); }
/* Waiting on a signature from a person who has everything they need. */
.flag-sign  { color: #6AA9F5; border-color: rgba(106, 169, 245, .38);
  background: rgba(106, 169, 245, .10); }
/* With somebody else entirely. Quietest: there is nothing to do about it. */
.flag-wait  { color: var(--txt-3); border-color: var(--edge); }

/* The stage filter above the list. */
.filters { display: flex; flex-wrap: wrap; gap: 7px; padding: 12px 17px 0; }
.chip {
  font: inherit; font-size: 12.5px;
  border: 1px solid var(--edge); background: transparent; color: inherit;
  border-radius: 999px; padding: 5px 12px; cursor: pointer;
}
.chip.on { border-color: var(--edge-2); background: rgba(128, 128, 128, .12); font-weight: 600; }
