/*
 * The order desk.
 *
 * Written for somebody who sits in front of it all day, which sets most of the
 * decisions here: the table is dense, the row you are pointing at is obvious,
 * and nothing moves under the cursor while data loads. Colours come from the
 * app so the two screens read as one product.
 *
 * Dark mode follows the operating system. A shop working late should not be
 * handed a white screen because nobody thought about it.
 */

:root {
	--nm-bg: #f6f7f9;
	--nm-surface: #ffffff;
	--nm-raised: #fbfbfc;
	--nm-border: #e3e5e9;
	--nm-line: #eef0f3;
	/* Every second row. Deliberately faint — it is a rhythm, not a border,
	   and text sits on it, so it has to leave the 4.5:1 pairs alone. */
	--nm-band: #f7f8fa;
	/* Between one group of columns and the next. This one is a real
	   boundary and is allowed to be seen. */
	--nm-divide: #8d9093;
	--nm-text: #14161a;
	--nm-muted: #626873;
	/* Measured, not picked. The first value was 3.17:1 on white — and this is
	   the colour the 11px labels and timestamps use, which is exactly where
	   contrast matters most. 4.5:1 against every surface it sits on. */
	--nm-faint: #6c727d;
	--nm-primary: #0f766e;
	--nm-primary-soft: #e6f4f1;
	--nm-danger: #b42318;
	--nm-danger-soft: #fdecea;
	--nm-warn: #b54708;
	--nm-warn-soft: #fef6ee;
	--nm-good: #067647;
	--nm-good-soft: #ecfdf3;
	--nm-shadow: 0 8px 24px rgba(16, 24, 40, 0.16);
	--nm-radius: 8px;

	/*
	 * Type scale, with real steps between them.
	 *
	 * The first version had seven sizes from 10px to 16px — every jump about
	 * 1.08, which is no hierarchy at all: nothing looked more important than
	 * anything else because nothing was. These are roughly 1.2 to 1.3 apart,
	 * which is the point where a difference reads as a decision.
	 *
	 * Five steps, and no size outside them. A sixth would be a sign that one of
	 * these five is doing the wrong job.
	 */
	--t-micro: 11px;   /* column headers, sub-labels — the quietest thing on screen */
	--t-body: 13px;    /* everything inside a row */
	--t-lead: 16px;    /* drawer titles, the brand */
	--t-figure: 21px;  /* the summary numbers, which are the point of the bar */
	--t-title: 26px;   /* reserved */

	/*
	 * Spacing, on a scale rather than by eye. There were twelve different
	 * padding values before this, which is not a rhythm — it is twelve separate
	 * guesses.
	 */
	--s-1: 4px;
	--s-2: 8px;
	--s-3: 12px;
	--s-4: 16px;
	--s-5: 24px;
	--s-6: 32px;
}

@media (prefers-color-scheme: dark) {
	:root {
		--nm-bg: #0d0f12;
		--nm-surface: #16191d;
		--nm-raised: #1c2025;
		--nm-border: #2a2f36;
		--nm-line: #23272d;
		/* Darker than the surface, not lighter: --nm-raised is the hover, and
		   a band that matched it would make every other row look hovered. */
		--nm-band: #121418;
		--nm-divide: #626568;
		--nm-text: #e8eaed;
		--nm-muted: #9aa1ac;
		--nm-faint: #808792;
		--nm-primary: #2dd4bf;
		--nm-primary-soft: #103b37;
		--nm-danger: #f97066;
		--nm-danger-soft: #3d1a17;
		--nm-warn: #fdb022;
		--nm-warn-soft: #3a2410;
		--nm-good: #47cd89;
		--nm-good-soft: #10301f;
		--nm-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
	}
}

* { box-sizing: border-box; }

html, body {
	margin: 0;
	padding: 0;
	height: 100%;
}

.nm-body {
	background: var(--nm-bg);
	color: var(--nm-text);
	font: var(--t-body)/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans Bengali", sans-serif;
	/* Bangla and Latin sit at different optical sizes; this keeps numerals
	   lining up in the money columns whichever the row is written in. */
	font-variant-numeric: tabular-nums;
	-webkit-font-smoothing: antialiased;
}

.nm-root { min-height: 100%; display: flex; flex-direction: column; }

.nm-boot,
.nm-empty,
.nm-error {
	padding: 48px 24px;
	text-align: center;
	color: var(--nm-muted);
}

.nm-error { color: var(--nm-danger); }

/* A refusal stated inside a form, as against .nm-error's empty state. The
   thing being refused is still on screen underneath it, so this one is boxed
   and left aligned rather than centred in a field of white. Measured: 5.75:1
   on the soft ground, both themes. */
.nm-refusal {
	background-color: var(--nm-danger-soft);
	color: var(--nm-danger);
	border-radius: 6px;
	padding: var(--s-2) var(--s-3);
}

/* ---------------------------------------------------------------- header */

.nm-head {
	background: var(--nm-surface);
	border-bottom: 1px solid var(--nm-border);
	position: sticky;
	top: 0;
	z-index: 30;
}

/*
 * One line, always, sliding when it will not fit.
 *
 * It used to overflow silently above 720px — 1,174px of content in a 753px box
 * with nothing to scroll it, so Settings and Sign out were off the edge and
 * unreachable — and wrap below it, taking six lines on a phone. The tab strip
 * underneath has slid since the beginning and stays one line at every width;
 * this is that, applied to the row above it.
 */
.nm-head-top {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 16px;
	overflow-x: auto;
	scrollbar-width: thin;
}

/* Only the spacer gives ground. Everything else keeps its size and lets the
   row slide, rather than being squeezed into something unreadable. */
.nm-head-top > :not(.nm-spacer):not(.nm-search) { flex: 0 0 auto; }

.nm-brand {
	font-weight: 700;
	font-size: var(--t-lead);
	letter-spacing: -0.01em;
	white-space: nowrap;
}

.nm-brand span { color: var(--nm-faint); font-weight: 400; }

.nm-spacer { flex: 1; }

.nm-search {
	position: relative;
	flex: 0 1 340px;
	min-width: 160px;
}

.nm-search input {
	width: 100%;
	padding: 7px 28px 7px 11px;
	border: 1px solid var(--nm-border);
	border-radius: var(--nm-radius);
	background: var(--nm-bg);
	color: var(--nm-text);
	font: inherit;
}

.nm-search input:focus {
	outline: 2px solid var(--nm-primary);
	outline-offset: -1px;
	background: var(--nm-surface);
}

.nm-search button {
	position: absolute;
	right: 4px;
	top: 50%;
	transform: translateY(-50%);
	border: 0;
	background: none;
	color: var(--nm-faint);
	cursor: pointer;
	font-size: var(--t-lead);
	line-height: 1;
	padding: 4px 6px;
}

/* ----------------------------------------------------------------- tabs */

.nm-tabs {
	display: flex;
	gap: 4px;
	padding: 0 12px 8px;
	overflow-x: auto;
	scrollbar-width: thin;
}

/*
 * The three rows of the head all slide, so all three carry a scrollbar on a
 * narrow screen. At the browser default that is three grey slabs stacked above
 * the orders, which reads as furniture rather than as "there is more this way".
 * A hairline in the line colour still points, and stops competing.
 */
.nm-head-top,
.nm-tabs,
.nm-bar {
	scrollbar-color: var(--nm-border) transparent;
	overscroll-behavior-x: contain;
}

.nm-head-top::-webkit-scrollbar,
.nm-tabs::-webkit-scrollbar,
.nm-bar::-webkit-scrollbar { height: 6px; }

.nm-head-top::-webkit-scrollbar-track,
.nm-tabs::-webkit-scrollbar-track,
.nm-bar::-webkit-scrollbar-track { background: transparent; }

.nm-head-top::-webkit-scrollbar-thumb,
.nm-tabs::-webkit-scrollbar-thumb,
.nm-bar::-webkit-scrollbar-thumb {
	background: var(--nm-border);
	border-radius: 999px;
}

.nm-tab {
	display: inline-flex;
	align-items: center;
	gap: var(--s-1);
	padding: 6px var(--s-3);
	border: 1px solid transparent;
	border-radius: 999px;
	background: none;
	color: var(--nm-muted);
	font: inherit;
	font-size: var(--t-body);
	white-space: nowrap;
	cursor: pointer;
}

.nm-tab:hover { background: var(--nm-line); color: var(--nm-text); }

.nm-tab.is-on {
	background: var(--nm-primary);
	border-color: var(--nm-primary);
	color: #fff;
	font-weight: 600;
}

@media (prefers-color-scheme: dark) {
	.nm-tab.is-on { color: #06231f; }
	/* The selected tab carries dark text here, so the pill lightens instead. */
	.nm-tab.is-on b { background: rgba(255, 255, 255, 0.3); }
}

.nm-tab b {
	font-weight: 600;
	font-size: var(--t-micro);
	padding: 1px 6px;
	border-radius: 999px;
	background: var(--nm-line);
	color: var(--nm-muted);
}

.nm-tab.is-on b { background: rgba(0, 0, 0, 0.22); color: inherit; }

/* -------------------------------------------------------------- toolbar */

.nm-bar {
	display: flex;
	align-items: center;
	gap: 8px;
	/* Slides rather than wrapping. Wrapping took the head from 147px to 229px
	   between a desktop and a phone, and the height of the thing above the
	   orders is the one measurement that costs orders. */
	flex-wrap: nowrap;
	overflow-x: auto;
	scrollbar-width: thin;
	padding: 8px 16px;
	border-top: 1px solid var(--nm-line);
	background: var(--nm-raised);
}

.nm-bar > :not(.nm-spacer) { flex: 0 0 auto; }

.nm-stat {
	display: flex;
	align-items: baseline;
	gap: var(--s-1);
	font-size: var(--t-micro);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--nm-faint);
}

.nm-stat b { color: var(--nm-text); font-size: var(--t-figure); font-weight: 650; line-height: 1.1; }

.nm-sep { width: 1px; height: 18px; background: var(--nm-border); }

/* -------------------------------------------------------------- buttons */

.nm-btn {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 6px 11px;
	border: 1px solid var(--nm-border);
	border-radius: 6px;
	background: var(--nm-surface);
	color: var(--nm-text);
	font: inherit;
	font-size: var(--t-body);
	cursor: pointer;
	white-space: nowrap;
}

.nm-btn:hover:not(:disabled) { border-color: var(--nm-faint); }
.nm-btn:disabled { opacity: 0.5; cursor: default; }

.nm-btn.is-primary {
	background: var(--nm-primary);
	border-color: var(--nm-primary);
	color: #fff;
	font-weight: 600;
}

@media (prefers-color-scheme: dark) {
	.nm-btn.is-primary { color: #06231f; }
}

.nm-btn.is-quiet { border-color: transparent; background: none; color: var(--nm-muted); }
.nm-btn.is-quiet:hover:not(:disabled) { background: var(--nm-line); color: var(--nm-text); }

.nm-btn.is-danger { color: var(--nm-danger); }

/* ---------------------------------------------------------------- table */

.nm-wrap {
	flex: 1;
	overflow: auto;
	padding: 12px 16px 80px;
}

.nm-table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	background: var(--nm-surface);
	/* A defined border, and no shadow. The pairing of a hairline border with a
	   wide diffuse shadow is a generated-UI signature, and a table that sits in
	   the page is not floating above it — only the drawer and the toasts are. */
	border: 1px solid var(--nm-border);
	border-radius: var(--nm-radius);
	overflow: hidden;
	/* Declared widths, not a guess per cell. */
	table-layout: fixed;
}

.nm-table th {
	position: sticky;
	top: 0;
	z-index: 10;
	background: var(--nm-raised);
	/* The one line on the table that is a real boundary, so it is the one line
	   allowed to be seen. */
	border-bottom: 1px solid var(--nm-divide);
	padding: var(--s-2) var(--s-3);
	text-align: left;
	font-size: var(--t-micro);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--nm-faint);
	white-space: nowrap;
}

.nm-table td {
	padding: var(--s-2) var(--s-3);
	vertical-align: top;
	/* A child wider than its column would otherwise be painted over the next
	   one. An address did exactly that to a total. */
	overflow: hidden;
	/* And a long unbroken word wraps rather than pushing out. */
	overflow-wrap: anywhere;
}

/* Banding rather than a line. The line was #eef0f3 on white — 1.15:1, which
   nobody can see, so eighteen columns of similar text ran together. A band is
   a rhythm the eye follows without anything being drawn between rows. */
.nm-table tbody tr:nth-child(even) { background: var(--nm-band); }
.nm-table tbody tr:hover { background: var(--nm-raised); }
.nm-table tbody tr.is-picked { background: var(--nm-primary-soft); }

/* Where one kind of information ends and the next begins: order and date, then
   who the customer is, then what they bought, then the money, then the parcel.
   Four lines on the screen instead of eighteen, and the eye has landmarks. */
.nm-table td.is-group,
.nm-table th.is-group { border-left: 1px solid var(--nm-divide); }

.nm-num { text-align: right; white-space: nowrap; }
.nm-nowrap { white-space: nowrap; }

/* One thing in a row is the thing you are looking for; everything else is
   there once you have found it. */
.nm-id { font-weight: 700; color: var(--nm-text); text-decoration: none; }
.nm-id:hover { color: var(--nm-primary); text-decoration: underline; }

.nm-sub { color: var(--nm-faint); font-size: var(--t-micro); }
.nm-strong { font-weight: 600; }

/* Long text that must not push the table wide. */
.nm-clip {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	/* Its own column, whatever that column happens to be. A fixed 260px here
	   was wider than most of them. */
	max-width: 100%;
}

.nm-clip.is-wide { max-width: 100%; }

/* An address is three lines of a real place, not two lines and an ellipsis. */
.nm-clip.is-tall { -webkit-line-clamp: 3; }

/* ------------------------------------------------------------- statuses */

.nm-pill {
	display: inline-block;
	padding: 2px var(--s-2);
	border-radius: 999px;
	font-size: var(--t-micro);
	font-weight: 600;
	white-space: nowrap;
	background: var(--nm-line);
	color: var(--nm-muted);
}

/* background-color, never the `background` shorthand: this pill is also the
   status <select>, and the shorthand resets the background-image its dropdown
   arrow is drawn with — so a coloured pill was losing its arrow. */
.nm-pill.slot-new,
.nm-pill.slot-incomplete { background-color: var(--nm-warn-soft); color: var(--nm-warn); }
.nm-pill.slot-confirmed,
.nm-pill.slot-waiting,
.nm-pill.slot-packed { background-color: var(--nm-primary-soft); color: var(--nm-primary); }
.nm-pill.slot-shipped { background-color: #eef4ff; color: #175cd3; }
.nm-pill.slot-delivered { background-color: var(--nm-good-soft); color: var(--nm-good); }
.nm-pill.slot-partial { background-color: var(--nm-warn-soft); color: var(--nm-warn); }
.nm-pill.slot-returned,
.nm-pill.slot-failed,
.nm-pill.slot-cancelled { background-color: var(--nm-danger-soft); color: var(--nm-danger); }

@media (prefers-color-scheme: dark) {
	.nm-pill.slot-shipped { background-color: #10233f; color: #84caff; }
}

/* --------------------------------------------------------------- selects */

.nm-select {
	border: 1px solid var(--nm-border);
	border-radius: 6px;
	background: var(--nm-surface);
	color: var(--nm-text);
	font: inherit;
	font-size: var(--t-micro);
	padding: var(--s-1) 6px;
	max-width: 150px;
}

.nm-select:disabled { opacity: 0.6; }

/*
 * A status pill that is also the control.
 *
 * It was a pill with a separate dropdown stacked underneath, which put two
 * form controls in every row and made the table read as a form. The pill is
 * the select now: same size, same colour, and the row is half the height.
 */
.nm-pick {
	width: auto;
	max-width: 100%;
	-webkit-appearance: none;
	appearance: none;
	border: 1px solid transparent;
	font-family: inherit;
	cursor: pointer;
	padding-right: var(--s-4);
	background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
		linear-gradient(135deg, currentColor 50%, transparent 50%);
	background-position: right 7px center, right 3px center;
	background-size: 4px 4px, 4px 4px;
	background-repeat: no-repeat;
}

.nm-pick:hover { border-color: currentColor; }
.nm-pick:focus { outline: 2px solid var(--nm-primary); outline-offset: 1px; }

/* Quiet until reached for: a column of forty bordered boxes is a wall. */
.nm-select.is-quiet {
	border-color: transparent;
	background-color: transparent;
	color: var(--nm-muted);
}

.nm-select.is-quiet:hover,
.nm-select.is-quiet:focus {
	border-color: var(--nm-border);
	background-color: var(--nm-surface);
	color: var(--nm-text);
}

/* A cell that is saving. Deliberately not a spinner that replaces the value:
   the old value stays readable so somebody can see what it was changing from. */
.nm-busy { opacity: 0.45; pointer-events: none; }

/* ----------------------------------------------------------------- notes */

.nm-note {
	border: 0;
	background: none;
	font: inherit;
	font-size: var(--t-micro);
	color: var(--nm-muted);
	text-align: left;
	cursor: pointer;
	padding: 0;
	max-width: 200px;
}

/* A note is a one-line label; a product list is not. The two share this
   class, and the blanket nowrap was quietly beating .nm-clip's two lines —
   which is why a product name was being cut mid-word with a whole empty line
   underneath it. */
.nm-note:not(.nm-clip) {
	white-space: nowrap;
}

/* The products cell: a line each, and a name too long for the column is cut
   on its own line rather than eating the one below it. */
.nm-prods {
	max-width: 100%;
	width: 100%;
}

.nm-prod {
	display: flex;
	align-items: flex-start;
	gap: 4px;
	max-width: 100%;
}

/* The name wraps rather than being cut: on one line, 53 of 58 product names on
   a real shop's list ended in an ellipsis, and "Baby Carrier Ergonomic Fro…"
   is not something anybody can pack from. Two lines fits almost all of them;
   past that the tooltip still has the whole thing. */
.nm-prod-n {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	min-width: 0;
	/* .nm-note sets nowrap on anything without .nm-clip, and inherited nowrap
	   beats a line clamp — the names went on being cut on one line while the
	   clamp sat there doing nothing. */
	white-space: normal;
}

.nm-prod-q {
	flex: none;
	color: var(--nm-faint);
}

.nm-prod + .nm-prod {
	margin-top: 1px;
}

.nm-prod.is-more {
	color: var(--nm-faint);
}

/* Row-size, row-colour, and it reacts. The two cells that open the drawer are
   the same size as the text around them, so hover is the only thing telling
   you they are not just text. */
.nm-opens {
	font-size: var(--t-body);
	color: var(--nm-text);
}

.nm-note:hover { color: var(--nm-primary); text-decoration: underline; }
.nm-note.is-empty { color: var(--nm-faint); font-style: italic; }

/* Scoped to the Note cell on purpose. `.nm-note` is also worn by the Products
   and Total cells, which open the same drawer and are styled for their own job;
   a bare `.nm-note.nm-clip` here would have quietly restyled Products too. */
.nm-last-note {
	max-width: 100%;
	width: 100%;
	color: var(--nm-text);
	line-height: 1.35;
	/* Row content, not a label. `.nm-note` is 11px because it began life as a
	   `Notes ›` button, and --t-micro is documented above as "the quietest
	   thing on screen" — wrong for the one cell that was asked to be readable
	   without opening anything. `.nm-opens` makes the same correction for
	   Products and Total, which wear the same class. */
	font-size: var(--t-body);
}

/* Who said it, on the same line as what they said — a second line would make
   every row with a note taller than every row without one. */
.nm-note-src {
	display: inline-block;
	padding: 0 4px;
	border-radius: 3px;
	background-color: var(--nm-line);
	color: var(--nm-muted);
	font-size: var(--t-micro);
	font-weight: 600;
	letter-spacing: .02em;
	/* Sits with the text rather than on it: the tag is context, the note is
	   the thing being read. */
	vertical-align: baseline;
}

/* The courier's word carries further than ours — it is the one that says a
   delivery is in trouble. Colour, not weight, so a page of rider notes does
   not read as a page of shouting. */
.nm-note-src.is-courier {
	background-color: var(--nm-warn-soft);
	color: var(--nm-warn);
}

/* Underlining two clamped lines is noise, and the row already lights up on
   hover. The colour shift alone says it is a way in. */
.nm-last-note:hover {
	text-decoration: none;
	color: var(--nm-primary);
}

/* ------------------------------------------------------------ pagination */

.nm-pager {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	padding: var(--s-4);
	color: var(--nm-muted);
	font-size: var(--t-body);
}

/* --------------------------------------------------------------- drawer */

.nm-scrim {
	position: fixed;
	inset: 0;
	background: rgba(12, 15, 20, 0.45);
	z-index: 60;
	display: flex;
	justify-content: flex-end;
}

.nm-drawer {
	width: min(520px, 100%);
	background: var(--nm-surface);
	height: 100%;
	overflow-y: auto;
	box-shadow: -8px 0 32px rgba(0, 0, 0, 0.18);
	display: flex;
	flex-direction: column;
}

.nm-drawer-head {
	position: sticky;
	top: 0;
	background: var(--nm-surface);
	border-bottom: 1px solid var(--nm-border);
	padding: 14px 16px;
	display: flex;
	align-items: center;
	gap: 10px;
	z-index: 2;
}

.nm-drawer-head h2 { margin: 0; font-size: var(--t-lead); }
.nm-drawer-body { padding: 16px; display: grid; gap: 14px; }

.nm-field { display: grid; gap: 5px; }
.nm-field label { font-size: var(--t-micro); font-weight: 600; color: var(--nm-muted); }

.nm-field input,
.nm-field textarea,
.nm-field select {
	width: 100%;
	padding: 7px 9px;
	border: 1px solid var(--nm-border);
	border-radius: 6px;
	background: var(--nm-bg);
	color: var(--nm-text);
	font: inherit;
}

.nm-field textarea { min-height: 84px; resize: vertical; }

.nm-log { display: grid; gap: 10px; }

.nm-log-item {
	/* A hairline, not a bar. A thick coloured rule down one side of a card is
	   the most recognisable tell of a generated interface; this is a timeline
	   rule, so it stays neutral and thin. */
	border-left: 1px solid var(--nm-line);
	padding-left: var(--s-3);
}

.nm-log-item time { display: block; font-size: var(--t-micro); color: var(--nm-faint); }

/* ---------------------------------------------------------------- toast */

.nm-toasts {
	position: fixed;
	left: 50%;
	bottom: 22px;
	transform: translateX(-50%);
	z-index: 90;
	display: grid;
	gap: 8px;
	width: min(560px, calc(100vw - 32px));
}

.nm-toast {
	background: #101828;
	color: #fff;
	padding: 10px 14px;
	border-radius: var(--nm-radius);
	box-shadow: 0 8px 24px rgba(16, 24, 40, 0.24);
	font-size: var(--t-body);
	display: flex;
	gap: var(--s-3);
	align-items: flex-start;
}

.nm-toast.is-bad { background: #b42318; }
.nm-toast.is-good { background: #067647; }
/* Amber, because the edit succeeded — red would say it did not. */
.nm-toast.is-warn { background: #b54708; }

/* ------------------------------------------------------------- popover */

/*
 * One small panel, anchored to the cell that opened it.
 *
 * A shadow and no border, because unlike the table this really is floating
 * above the page — the drawer and the toasts are the only other things that
 * are, and they are shadowed for the same reason.
 */
.nm-pop {
	position: fixed;
	z-index: 80;
	width: min(340px, calc(100vw - 24px));
	background: var(--nm-surface);
	border-radius: var(--nm-radius);
	box-shadow: var(--nm-shadow);
	color: var(--nm-text);
	font-size: var(--t-body);
}

.nm-pop-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-2);
	padding: var(--s-2) var(--s-3);
	border-bottom: 1px solid var(--nm-line);
}

.nm-pop-x {
	border: 0;
	background: none;
	color: var(--nm-muted);
	font-size: var(--t-lead);
	line-height: 1;
	padding: 0 var(--s-1);
	cursor: pointer;
	border-radius: 4px;
}

.nm-pop-x:hover { color: var(--nm-text); }

.nm-pop-body { padding: var(--s-3); }

.nm-pop-note { margin-bottom: var(--s-2); }
.nm-pop-note:last-child { margin: var(--s-2) 0 0; }

.nm-pop-table { width: 100%; border-collapse: collapse; }
.nm-pop-table td { padding: 3px 0; vertical-align: middle; }
.nm-pop-table td + td { padding-left: var(--s-2); }

.nm-pop-name { white-space: nowrap; max-width: 108px; overflow: hidden; text-overflow: ellipsis; }
.nm-pop-figure { font-weight: 600; white-space: nowrap; }
.nm-pop-bar { width: 100%; }

.nm-pop-table tr.is-total td { border-top: 1px solid var(--nm-line); padding-top: var(--s-2); font-weight: 600; }

.nm-pop-again { margin-top: var(--s-3); width: 100%; justify-content: center; }

/*
 * The bar repeats the figure beside it rather than replacing it, so nothing
 * here depends on telling one colour from another.
 *
 * Called a meter and not a bar: `.nm-bar` is the desk's toolbar and has been
 * since the beginning. Naming this one the same put `height: 6px` and
 * `overflow: hidden` on that toolbar and cut its buttons in half — CSS does
 * not care that they were meant to be different things.
 */
.nm-meter {
	height: 6px;
	border-radius: 999px;
	overflow: hidden;
	min-width: 40px;
}

.nm-meter-fill { height: 100%; border-radius: 999px; }

.nm-meter.is-good { background: var(--nm-good-soft); }
.nm-meter.is-good .nm-meter-fill { background: var(--nm-good); }
.nm-meter.is-warn { background: var(--nm-warn-soft); }
.nm-meter.is-warn .nm-meter-fill { background: var(--nm-warn); }
.nm-meter.is-danger { background: var(--nm-danger-soft); }
.nm-meter.is-danger .nm-meter-fill { background: var(--nm-danger); }

.nm-pop-figure.is-good { color: var(--nm-good); }
.nm-pop-figure.is-warn { color: var(--nm-warn); }
.nm-pop-figure.is-danger { color: var(--nm-danger); }

/* --------------------------------------------------------- courier record */

/*
 * The percentage in the row. Pill-shaped like a status, but it is a button:
 * pressing it opens the courier by courier report behind the number.
 */
.nm-rate {
	display: inline-flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 1px;
	padding: 2px 8px;
	border: 1px solid transparent;
	border-radius: 999px;
	background: none;
	font: inherit;
	cursor: pointer;
	text-align: left;
}

.nm-rate-figure { font-size: var(--t-body); font-weight: 650; line-height: 1.15; }
.nm-rate-of { font-size: var(--t-micro); opacity: 0.85; }

.nm-rate.is-good { background: var(--nm-good-soft); color: var(--nm-good); }
.nm-rate.is-warn { background: var(--nm-warn-soft); color: var(--nm-warn); }
.nm-rate.is-danger { background: var(--nm-danger-soft); color: var(--nm-danger); }

.nm-rate:hover { border-color: currentColor; }

/* -------------------------------------------------------------- loading */

/* currentColor, so it works on the selected tab and the unselected ones
   without a second rule per theme. */
.nm-tab.is-waiting::before {
	content: '';
	display: inline-block;
	width: 6px;
	height: 6px;
	margin-right: 6px;
	border-radius: 50%;
	background: currentColor;
	animation: nm-pulse 1s ease-in-out infinite;
	vertical-align: middle;
}

@keyframes nm-pulse {
	0%, 100% { opacity: 0.25; }
	50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
	.nm-tab.is-waiting::before { animation: none; opacity: 0.85; }
}


/*
 * Rows that are about to be replaced.
 *
 * Not hidden and not removed: the page would jump, and the row somebody is
 * reading would vanish under them. Dimmed, and no longer clickable, so nothing
 * is edited on data that is one request out of date.
 */
.nm-wrap.is-loading .nm-table {
	opacity: 0.5;
	pointer-events: none;
	transition: opacity 120ms linear;
}

.nm-progress {
	height: 3px;
	border-radius: 999px;
	overflow: hidden;
	background: var(--nm-line);
	margin-bottom: var(--s-2);
}

.nm-progress::after {
	content: '';
	display: block;
	width: 35%;
	height: 100%;
	border-radius: 999px;
	background: var(--nm-primary);
	animation: nm-slide 1.1s ease-in-out infinite;
}

@keyframes nm-slide {
	0%   { transform: translateX(-100%); }
	100% { transform: translateX(340%); }
}

/* Motion that reports state is still motion. Held still, the bar stays as a
   filled strip so the state is not lost with the animation. */
@media (prefers-reduced-motion: reduce) {
	.nm-progress::after { animation: none; width: 100%; opacity: 0.6; }
	.nm-wrap.is-loading .nm-table { transition: none; }
}

/* ------------------------------------------------------------------ misc */

.nm-spin {
	display: inline-block;
	width: 14px;
	height: 14px;
	border: 2px solid var(--nm-line);
	border-top-color: var(--nm-primary);
	border-radius: 50%;
	animation: nm-spin 0.7s linear infinite;
	vertical-align: -2px;
}

@keyframes nm-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
	.nm-spin { animation-duration: 3s; }
}

/* The table is wide by nature. On a narrow screen it scrolls sideways rather
   than reflowing — a packing desk on a laptop is the real case, and a fake
   card layout would just be a worse version of the app. */
@media (max-width: 720px) {
	.nm-wrap { padding: 8px; }
	/* The search box no longer takes a line of its own — the row slides now, so
	   giving it 100% would have made the very growth this avoids. It keeps a
	   usable width and moves along with everything else. */
	.nm-search { flex: 0 0 200px; }
}

/* ------------------------------------------------------------ edit cells */

/*
 * A cell somebody types in. Deliberately not styled as an input box: a table
 * of two hundred boxes is a form, and this is a list that happens to be
 * editable. The border appears on hover so it is discoverable, and on focus so
 * it is unmistakable.
 */
.nm-edit {
	display: block;
	min-width: 3rem;
	min-height: 1.3em;
	max-width: 100%;
	padding: 2px 5px;
	margin: -2px -5px;
	border: 1px solid transparent;
	border-radius: 4px;
	outline: none;
	white-space: pre-wrap;
}

/* Only the wide one wraps. A phone number split down the middle of its digits
   cannot be read aloud, and a thana broken into "Jatrab / ari" is not a place. */
.nm-nowrap .nm-edit { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* "Double Mooring" needs 107px in a 104px column, so it was arriving as
   "Double …". Two words on two lines is still the place; half of one is not.
   break-word, not anywhere: a single long thana breaks only if it cannot fit
   on a line by itself. */
.nm-zonecell .nm-edit {
	white-space: normal;
	overflow-wrap: break-word;
	text-overflow: clip;
}
.nm-edit.is-wide { word-break: break-word; }
.nm-edit.is-num { text-align: right; }

/* Under the Send button, offering somewhere to paste a number that was booked
   in the courier's own panel. Quieter than the button, because it is the
   second thing you would want, not the first. */
.nm-edit.is-quiet { font-size: var(--t-micro); }

.nm-edit.is-wide { max-width: 100%; }
.nm-edit:hover { border-color: var(--nm-border); background: var(--nm-bg); }

.nm-edit:focus {
	border-color: var(--nm-primary);
	background: var(--nm-surface);
	box-shadow: 0 0 0 3px var(--nm-primary-soft);
	white-space: normal;
}

.nm-edit:empty::before {
	content: '—';
	color: var(--nm-faint);
}

.nm-edit[data-placeholder]:empty::before {
	content: attr(data-placeholder);
	color: var(--nm-faint);
}

/* Held briefly after a save so somebody tabbing down a column can see which
   rows actually took. */
.nm-edit.nm-saved {
	border-color: var(--nm-good);
	background: var(--nm-good-soft);
}

/* ---------------------------------------------------------------- alerts */

.nm-bell { position: relative; }

.nm-badge {
	background: var(--nm-danger);
	color: #fff;
	font-size: var(--t-micro);
	font-weight: 800;
	padding: 1px 5px;
	border-radius: 999px;
	margin-left: 2px;
}

.nm-alert {
	display: block;
	width: 100%;
	text-align: left;
	border: 0;
	background: none;
	color: var(--nm-text);
	font: inherit;
	padding: var(--s-2) 0 var(--s-2) var(--s-4);
	position: relative;
	cursor: pointer;
}

.nm-alert:hover { background: var(--nm-raised); }

/*
 * Unread is a dot and a weight.
 *
 * It was a coloured bar down the left edge, which is the single most
 * recognisable signature of a generated interface — and the app's own
 * notification list already used a dot, so the two screens now agree.
 */
.nm-alert.is-unread::before {
	content: '';
	position: absolute;
	left: 2px;
	top: 14px;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--nm-primary);
}

.nm-alert.is-unread .nm-strong { font-weight: 700; }

/* ------------------------------------------------------- order lines */

.nm-lines {
	border: 1px solid var(--nm-border);
	border-radius: 6px;
	overflow: hidden;
}

.nm-line {
	display: grid;
	grid-template-columns: 1fr 4.5rem 5.5rem 5rem;
	gap: var(--s-2);
	align-items: center;
	padding: var(--s-2) var(--s-3);
	border-bottom: 1px solid var(--nm-line);
}

.nm-line:last-child { border-bottom: 0; }
.nm-line-name { min-width: 0; }
.nm-line-name .nm-strong { overflow-wrap: anywhere; }

.nm-qty,
.nm-price {
	width: 100%;
	padding: var(--s-1) 6px;
	border: 1px solid var(--nm-border);
	border-radius: 6px;
	background: var(--nm-bg);
	color: var(--nm-text);
	font: inherit;
	font-size: var(--t-body);
	text-align: right;
}

.nm-qty:focus,
.nm-price:focus {
	outline: 2px solid var(--nm-primary);
	outline-offset: -1px;
	background: var(--nm-surface);
}

.nm-line-total { font-weight: 600; }

.nm-mini { width: 100%; }
.nm-mini td { padding: 3px 0; }

/* On a narrow drawer the four columns stop fitting side by side. */
@media (max-width: 520px) {
	.nm-line { grid-template-columns: 1fr 4rem 5rem; }
	.nm-line-total { grid-column: 2 / -1; text-align: right; }
}

/* ------------------------------------------------------- dates, keys */

.nm-dates {
	display: flex;
	align-items: center;
	gap: var(--s-1);
	white-space: nowrap;
}

.nm-dates input {
	padding: 6px var(--s-2);
	border: 1px solid var(--nm-border);
	border-radius: 6px;
	background: var(--nm-bg);
	color: var(--nm-text);
	font: inherit;
	font-size: var(--t-micro);
}

.nm-key {
	display: inline-block;
	min-width: 1.6rem;
	padding: 2px 6px;
	border: 1px solid var(--nm-border);
	border-bottom-width: 2px;
	border-radius: 4px;
	background: var(--nm-raised);
	font: inherit;
	font-size: var(--t-micro);
	text-align: center;
}

/* The row the keyboard is on. A rule down the left rather than a fill, so it
   does not fight the selection colour when a row is both. */
.nm-table tbody tr.is-cursor td:first-child { box-shadow: inset 3px 0 0 var(--nm-primary); }

/* ------------------------------------------------------------ skeleton */

/*
 * The shape of the table while it loads, rather than a blank panel. The page
 * does not jump when the rows arrive, because the rows were already the right
 * size. No shimmer: a moving gradient across eight rows is decoration, and the
 * point of this is to be ignored.
 */
.nm-skeleton .nm-bone {
	display: block;
	height: 10px;
	border-radius: 3px;
	background: var(--nm-line);
}

.nm-skeleton tbody tr:nth-child(even) .nm-bone { opacity: 0.6; }

/* -------------------------------------------------- sorting and density */

.nm-sort {
	border: 0;
	background: none;
	color: inherit;
	font: inherit;
	letter-spacing: inherit;
	text-transform: inherit;
	padding: 0;
	cursor: pointer;
}

.nm-sort:hover { color: var(--nm-text); }
.nm-table th.is-sorted { color: var(--nm-primary); }

/* Compact. For the thirteen-inch laptop this is actually worked on, where
   the difference is four more orders on screen without scrolling. */
.nm-table.is-dense td { padding: 4px 8px; }
.nm-table.is-dense th { padding: 6px 8px; }
.nm-table.is-dense .nm-sub { font-size: 10px; }
.nm-table.is-dense .nm-clip { -webkit-line-clamp: 1; }
.nm-table.is-dense .nm-clip.is-tall { -webkit-line-clamp: 2; }

/* Totals for the page, held apart from the rows so nobody reads one as
   another order. */
.nm-table tfoot td {
	position: sticky;
	bottom: 0;
	background: var(--nm-raised);
	border-top: 1px solid var(--nm-border);
	padding: 8px 10px;
}

.nm-undo {
	margin-left: auto;
	border: 1px solid rgba(255, 255, 255, 0.4);
	border-radius: 6px;
	background: none;
	color: inherit;
	font: inherit;
	font-size: var(--t-micro);
	font-weight: 700;
	padding: 3px 10px;
	cursor: pointer;
	white-space: nowrap;
}

.nm-undo:hover { background: rgba(255, 255, 255, 0.16); }

/* --- Column list: shown-or-not and in-what-order, in one list ------------ */

.nm-collist {
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.nm-colrow {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	padding: var(--s-1) var(--s-2);
	border-radius: 6px;
	background: var(--nm-surface);
}

.nm-colrow:hover { background: var(--nm-line); }

/* Half-visible while it is being carried, so the gap it leaves is legible. */
.nm-colrow.is-dragging { opacity: 0.4; }

/* Where it would land. A line rather than a filled row: the row underneath
   still has to be readable while deciding. */
.nm-colrow.is-over { box-shadow: inset 0 2px 0 0 var(--nm-accent); }

.nm-grip {
	cursor: grab;
	color: var(--nm-faint);
	font-size: var(--t-body);
	line-height: 1;
	user-select: none;
}

.nm-colrow.is-dragging .nm-grip { cursor: grabbing; }

.nm-colname {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	flex: 1;
	min-width: 0;
	font-size: var(--t-body);
	cursor: pointer;
}

.nm-colname input:disabled { cursor: default; }

.nm-colmove {
	padding: 0 var(--s-2);
	line-height: 1.6;
}

/* --- Suggested zone ------------------------------------------------------ */

.nm-zonecell { display: flex; align-items: center; gap: var(--s-1); }

/*
 * The suggestion carries the name it would write, so accepting it needs no
 * second look. Dashed, because it is not there yet.
 */
.nm-zoneguess {
	font: inherit;
	font-size: var(--t-micro);
	padding: 1px var(--s-2);
	border: 1px dashed var(--nm-border);
	border-radius: 999px;
	background: none;
	color: var(--nm-muted);
	cursor: pointer;
	white-space: nowrap;
}

.nm-zoneguess:hover:not(:disabled) { border-style: solid; color: var(--nm-text); background: var(--nm-line); }
.nm-zoneguess:disabled { opacity: 0.5; cursor: default; }

/* Found as its own word in the address, rather than inside a longer one. */
.nm-zoneguess.is-sure { color: var(--nm-text); border-color: var(--nm-muted); }

/* --- Sat here too long --------------------------------------------------- */

/*
 * Under the status, in the colour used for everything that needs somebody.
 * No icon and no badge: it appears on a handful of rows, and on those rows it
 * is the only red thing on the line.
 */
.nm-stall {
	margin-top: 2px;
	font-size: var(--t-micro);
	font-weight: 600;
	color: var(--nm-danger);
	white-space: nowrap;
}

/* --- Fraud check drawer -------------------------------------------------- */

/*
 * A section heading inside a drawer. Not .nm-drawer-head — that one is the
 * sticky title bar at the top, and reusing it here would stick two more bars
 * to the ceiling.
 */
.nm-subhead {
	margin: var(--s-2) 0 0;
	font-size: var(--t-micro);
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: var(--nm-muted);
}

/* One courier's line: name on the left, its numbers on the right. */
.nm-kv {
	display: flex;
	justify-content: space-between;
	gap: var(--s-3);
	padding: var(--s-1) 0;
	border-top: 1px solid var(--nm-line);
	font-size: var(--t-body);
}

.nm-kv span:first-child { text-transform: capitalize; }
.nm-kv span:last-child { color: var(--nm-muted); white-space: nowrap; }

/* Something the shop should not walk past. */
.nm-bad { color: var(--nm-danger); font-weight: 600; }

/* Choosing where a parcel goes, when the courier routes on ids rather than on
   the written address. One level at a time, because a zone list belongs to one
   city — showing another city's zones is how a parcel reaches the wrong hub. */
.nm-place-back {
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, 0.45);
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 9999;
}

.nm-place {
	background: var(--nm-surface, #fff);
	border-radius: 10px;
	padding: 16px;
	width: min(420px, 92vw);
	max-height: 80vh;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.nm-place h3 { margin: 0; }

.nm-place-search { width: 100%; }

.nm-place-list {
	overflow-y: auto;
	flex: 1;
	min-height: 120px;
}

.nm-place-row {
	display: block;
	width: 100%;
	text-align: left;
	padding: 10px 8px;
	border: 0;
	border-bottom: 1px solid var(--nm-line, #eef0f3);
	background: none;
	cursor: pointer;
	font: inherit;
}

.nm-place-row:hover { background: var(--nm-band, #f7f8fa); }
