/*
 * Mohair Connect — the component set of phase 0b (plan 10.2–10.6), on top of
 * tokens.css (borrowed) and connect.css (the shell). Colours only via tokens;
 * Connect's own tokens (status, documents) are defined here, light and dark.
 *
 * Glass budget (plan 10.1): nothing in this file blurs, except the sheet's and
 * the dialog's backdrop and the search overlay — the shell does the rest.
 * Bubbles, nodes, rows and cards are opaque blends.
 */

/* ---------- Connect's own tokens ---------- */

:root {
  --st-idle: var(--ink-3);
  --st-sent: var(--accent);
  --st-confirmed: #2a6fc0;
  --st-ready: #2e7d4f;
  --st-shipped: #1f7a8c;
  --st-received: #1f5f3a;
  --st-cancelled: var(--bad);
  --st-change: var(--warn);
  --dok-order: var(--accent);
  --dok-confirmation: var(--st-confirmed);
  --dok-packing: var(--st-shipped);
  --dok-invoice: var(--oek-ind);
  --dok-credit: var(--oek-ind);
  --rec: #d0342c;
  /* Phase 2e: the turn of the year in the timeline — a red of its own, never --bad (that means an error).
     3:1 as a line and 4.5:1 as the year's number on the timeline in every look (kontrast.test.mjs). */
  --year-line: #c8252c;
  --tone: 12%;
  --tail: 6px;
  /* Accent words on an accent tint (a "To:" mark, a chosen chip, a reply's name): a quarter ink mixed
     in, like the status words, so they read at 4.5:1 in Night too. On a plain card, --accent is enough. */
  --accent-text: color-mix(in srgb, var(--accent) 75%, var(--ink));
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="hoer"]) {
    --st-confirmed: #5a93db;
    --st-ready: #6cc38f;
    --st-shipped: #4fb3c6;
    --st-received: #4f9d6d;
    --rec: #ff6b5e;
    --year-line: #ff6f6f;
  }
}
:root[data-theme="dark"] {
  --st-confirmed: #5a93db;
  --st-ready: #6cc38f;
  --st-shipped: #4fb3c6;
  --st-received: #4f9d6d;
  --rec: #ff6b5e;
  --year-line: #ff6f6f;
}
/* Light ("Hør"): muted text one step darker, so it reads at 4.5:1 on a card (kontrast.test.mjs). */
:root[data-theme="hoer"] {
  --ink-3: #72675a;
  --year-line: #b5262a;
}
/*
 * Words and glyphs in a status or document colour are that colour with a quarter of the ink
 * mixed in: the hue stays, and it reads at 4.5:1 (words) and 3:1 (glyphs) on its own 12 % tone
 * in every look — the plan's colours alone reach 3.8:1 (kontrast.test.mjs proves the mix).
 */
.status,
.doc-tile,
.notice {
  --c-ink: color-mix(in srgb, var(--c) 75%, var(--ink));
}

/* A sentence that needs an eye on it — "VBM asked for a change — your answer is needed." — and its way to it. */
.notice {
  --c: var(--st-change);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: 0 0 12px;
  padding: 8px 8px 8px 12px;
  border-radius: var(--r-s);
  font-size: 14px;
  font-weight: 560;
  color: var(--ink);
  background: color-mix(in srgb, var(--c) var(--tone), transparent);
}
.notice > svg {
  flex: none;
  color: var(--c-ink);
}
.notice > span {
  flex: 1;
  min-width: 180px;
}

.spacer {
  flex: 1;
}

/* An opaque blend for everything inside the shell (plan 10.1). */
.blend {
  background: color-mix(in srgb, var(--surface) 92%, var(--accent));
  box-shadow: var(--shadow-s), inset 0 0 0 1px var(--glass-line);
}

/* ---------- status chips and document glyphs (plan 10.5: always icon + word) ---------- */

.status {
  --c: var(--st-idle);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 10px 0 8px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--c-ink);
  background: color-mix(in srgb, var(--c) var(--tone), transparent);
  white-space: nowrap;
}
.status::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--c);
}
.status.st-sent { --c: var(--st-sent); }
.status.st-confirmed { --c: var(--st-confirmed); }
.status.st-ready { --c: var(--st-ready); }
.status.st-shipped { --c: var(--st-shipped); }
.status.st-received { --c: var(--st-received); }
.status.st-cancelled { --c: var(--st-cancelled); }
.status.st-change { --c: var(--st-change); }

.doc-tile {
  --c: var(--dok-order);
  flex: none;
  width: 28px;
  height: 28px;
  display: inline-grid;
  place-items: center;
  border-radius: 8px;
  color: var(--c-ink);
  background: color-mix(in srgb, var(--c) var(--tone), transparent);
}
.doc-tile.large {
  width: 40px;
  height: 40px;
  border-radius: 12px;
}
.doc-tile.d-confirmation { --c: var(--dok-confirmation); }
.doc-tile.d-packing { --c: var(--dok-packing); }
.doc-tile.d-invoice { --c: var(--dok-invoice); }
.doc-tile.d-credit { --c: var(--dok-credit); }
.doc-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 560;
}

/* ---------- the order's journey: pill on cards, stepper on the page (plan 10.2) ---------- */

/* On a card: the step's dot and word, then whose turn it is — no row of dots (review 0b). */
.journey {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 4px;
  min-height: 28px;
  padding: 4px 12px 4px 10px;
  border-radius: 14px;
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 13px;
  color: var(--ink-2);
}
.journey::before {
  content: "";
  flex: none;
  align-self: center;
  width: 8px;
  height: 8px;
  margin-right: 4px;
  border-radius: 50%;
  background: var(--c, var(--accent));
}
.journey b {
  color: var(--ink);
  font-weight: 600;
}
.journey b::after {
  content: " ·";
  font-weight: 400;
  color: var(--ink-3);
}

.stepper {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
}
.step {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 4px;
  text-align: center;
  padding-top: 0;
}
/* The track: 2 px from this node to the next, filled up to the current one. */
.step:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 13px;
  left: calc(50% + 18px);
  right: calc(-50% + 18px);
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--accent) var(--fill, 0%), var(--line) var(--fill, 0%));
}
.step.done:not(:last-child)::after {
  --fill: 100%;
}
.step.filling:not(:last-child)::after {
  animation: track-fill var(--slow) var(--ease) forwards;
}
@property --fill {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}
@keyframes track-fill {
  from { --fill: 0%; }
  to { --fill: 100%; }
}
.step-node {
  position: relative;
  z-index: 1;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 650;
  color: var(--ink-3);
  background: var(--surface);
  box-shadow: inset 0 0 0 2px var(--line);
}
.step.done .step-node {
  color: var(--accent-ink);
  background: var(--accent);
  box-shadow: none;
}
.step.now .step-node {
  color: var(--accent);
  background: var(--surface);
  box-shadow: inset 0 0 0 2px var(--accent), 0 0 0 5px var(--accent-soft);
}
.step.now.landed .step-node {
  animation: node-pop var(--mid) var(--spring);
}
@keyframes node-pop {
  from { transform: scale(0.6); }
}
.step-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.step:not(.done):not(.now) .step-label {
  color: var(--ink-3);
  font-weight: 560;
}
.step-date {
  font-size: 12px;
  color: var(--ink-3);
}
.step-date b {
  color: var(--ink);
  font-weight: 650;
}
/* What the current step means and whose turn it is: under the bar on a wide screen, inside the step on a phone. */
.step-next {
  display: grid;
  justify-items: start;
  gap: 4px;
  font-size: 14px;
  color: var(--ink-2);
}
.step-next p {
  margin: 0;
}
.step-next b {
  color: var(--ink);
  font-weight: 650;
}
.step-next .button {
  margin-top: 6px;
}
.step-next:focus {
  outline: none;
}
.step-next:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.step-hint {
  font-size: 12.5px;
  color: var(--ink-3);
}
.step-next.below {
  margin-top: 16px;
  padding: 12px 14px;
  border-radius: var(--r-m);
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.step-next.inside {
  display: none;
}

/* Phone: the journey runs downwards, 44 px a step, and the current step says what is next. */
@media (max-width: 640px) {
  .stepper {
    grid-auto-flow: row;
    grid-auto-columns: auto;
  }
  .step {
    grid-template-columns: 28px 1fr;
    justify-items: start;
    align-items: center;
    column-gap: 12px;
    row-gap: 2px;
    min-height: 44px;
    text-align: left;
  }
  .step-node {
    grid-row: span 2;
  }
  .step:not(:last-child)::after {
    top: 34px;
    bottom: -10px;
    left: 13px;
    right: auto;
    width: 2px;
    height: auto;
    background: linear-gradient(180deg, var(--accent) var(--fill, 0%), var(--line) var(--fill, 0%));
  }
  .step.now .step-next.inside {
    display: grid;
    grid-column: 2;
    margin: 6px 0 10px;
  }
  .step-next.below {
    display: none;
  }
}

/* One line per shipment: how and how many, ONE state chip, and the next step when it is yours. */
.shipment {
  display: flex;
  align-items: center;
  gap: 8px 12px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-radius: var(--r-m);
  font-size: 14px;
}
.shipment > svg {
  flex: none;
  color: var(--ink-2);
}
.shipment-text {
  flex: 1;
  min-width: 180px;
}
/* Samil's next step for this shipment, on its own row: "Next: the packing list, then mark it as shipped." + the button. */
.shipment-next {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  padding-left: 32px;
  font-size: 13.5px;
  color: var(--ink-2);
}
.ship-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  width: 100%;
}
.ship-form .slot-actions {
  grid-column: 1 / -1;
}

/* ---------- document places (plan 10.2: your turn · waiting · filled) ---------- */

.doc-slot {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px 14px;
  align-items: start;
  padding: 16px;
  border-radius: var(--r-l);
  overflow: hidden;
}
.doc-slot h4 {
  margin: 0;
  font-size: 15px;
  font-weight: 650;
}
.doc-slot p {
  margin: 2px 0 0;
  font-size: 13.5px;
  color: var(--ink-2);
}
.doc-slot.your-turn {
  background: color-mix(in srgb, var(--surface) 94%, var(--accent));
  box-shadow: none;
  outline: 1.5px dashed var(--accent);
  outline-offset: -1.5px;
}
.doc-slot.your-turn .doc-tile {
  --c: var(--accent);
}
.doc-slot.waiting {
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.doc-slot.waiting .doc-tile {
  --c: var(--ink-3);
}
.doc-slot.drop-over {
  outline-width: 2px;
  outline-style: solid;
  background: var(--accent-soft);
}
/* Your turn: numbered rows — 1 the file, 2 and 3 the place's own fields (review 0b). */
.slot-steps {
  grid-column: 2;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: slot;
  display: grid;
  gap: 12px;
}
.slot-steps > li {
  counter-increment: slot;
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: 10px;
  align-items: start;
}
.slot-steps > li::before {
  content: counter(slot);
  width: 24px;
  height: 24px;
  margin-top: 2px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 700;
  color: var(--accent);
  background: var(--surface);
  box-shadow: inset 0 0 0 1.5px var(--accent);
}
.slot-steps.single > li {
  grid-template-columns: minmax(0, 1fr);
}
.slot-steps.single > li::before {
  display: none;
}
.slot-step {
  display: grid;
  gap: 4px;
  min-width: 0;
}
.field-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
}
.slot-step-what {
  display: flex;
  align-items: center;
  gap: 6px 10px;
  flex-wrap: wrap;
}
/* Nothing to drop with on a touch screen. */
@media (pointer: coarse) {
  .drop-hint {
    display: none;
  }
}
.doc-slot:focus {
  outline: none;
}
.slot-file {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: 13.5px;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.slot-file > svg {
  flex: none;
  color: var(--good);
}
.slot-file b {
  color: var(--ink);
  font-weight: 600;
}
.slot-hint {
  font-size: 12.5px;
  font-weight: 400;
  color: var(--ink-3);
}
.slot-missing {
  font-size: 13px;
  color: var(--ink-2);
}
.slot-actions {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 8px 12px;
  flex-wrap: wrap;
}
@media (max-width: 480px) {
  .doc-slot {
    grid-template-columns: minmax(0, 1fr);
  }
  .slot-steps,
  .slot-actions {
    grid-column: 1;
  }
}
.slot-meta {
  font-size: 12.5px;
  color: var(--ink-3);
}
.slot-progress {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  width: var(--p, 0%);
  background: var(--accent);
  transition: width var(--fast) linear;
}
.slot-percent {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent);
}
.check-pop {
  animation: check-pop var(--mid) var(--spring);
}
@keyframes check-pop {
  0% { transform: scale(0.4); opacity: 0; }
  60% { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1); }
}

.field {
  display: grid;
  gap: 4px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
}
.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 40px;
  padding: 8px 12px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 400;
}
.field textarea {
  min-height: 72px;
  resize: vertical;
}

/* ---------- a change request (plan 10.2) ---------- */

.change-card {
  display: grid;
  gap: 12px;
  padding: 16px;
  border-radius: var(--r-l);
}
.change-card > h4 {
  margin: 0;
  font-size: 15px;
  font-weight: 650;
}
/* Each line: what · before → after · one word for what happened; the total last (review 0b). */
.diff {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 4px;
  font-size: 14px;
}
.diff li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 88px;
  align-items: center;
  gap: 4px 12px;
  padding: 6px 10px;
  border-radius: var(--r-s);
  background: var(--glass-soft);
}
.diff li > .status {
  justify-self: start;
}
.diff li.total {
  background: transparent;
  box-shadow: inset 0 1px 0 var(--line);
  border-radius: 0;
  font-weight: 650;
}
.diff .delta {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 480px) {
  .diff li {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  .diff .what {
    grid-column: 1 / -1;
  }
}
/* What each answer does, said before it is given (review 0b, round 2). */
.change-hint {
  display: grid;
  gap: 2px;
  margin: -2px 0 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
  color: var(--ink-2);
}
.change-hint b {
  color: var(--ink);
  font-weight: 650;
}
.change-result {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 14px;
  font-weight: 560;
}
.change-result:focus {
  outline: none;
}
.diff .delta s {
  color: var(--ink-3);
}
.diff .delta b {
  font-weight: 650;
}
.change-note {
  margin: 0;
  padding: 8px 12px;
  border-left: 3px solid var(--warn);
  font-size: 14px;
  color: var(--ink-2);
}
.change-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

/* ---------- the kg field (plan 10.2: 72×44, −/+ in whole dye lots) ---------- */

.kg {
  display: inline-grid;
  grid-template-columns: 32px 72px 32px;
  align-items: center;
  gap: 2px;
}
.kg-step {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
.kg-step:hover {
  color: var(--accent);
  background: var(--accent-softer);
}
.kg input {
  width: 72px;
  height: 44px;
  padding: 0 8px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--glass-soft);
  color: var(--ink-3);
  font: inherit;
  font-size: 15px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.kg.ordered input {
  color: var(--ink);
  font-weight: 600;
  background: var(--accent-soft);
  border-color: var(--accent);
}
.kg.wrong input {
  border-color: var(--warn);
  background: var(--warn-soft);
}
/* Under a lone field the line wraps inside its width; in a phone's list row it may reach left, over the free space. */
.kg-help {
  grid-column: 1 / -1;
  font-size: 12.5px;
  text-align: center;
  color: var(--ink-3);
}
.kg-help:empty,
.kg.bare .kg-help {
  display: none;
}
.order-list .kg-help {
  justify-self: end;
  width: max-content;
}
.kg-fix {
  grid-column: 1 / -1;
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  width: max-content;
  max-width: 260px;
  font-size: 12.5px;
  color: var(--ink-2);
}
.kg-fix:empty {
  display: none;
}
.fix-choices {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
/* Under a lone field: the sentence wraps inside the field's own width, the two buttons under it — never over a neighbour. */
.kg > .kg-fix {
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  width: auto;
  max-width: none;
}
.kg > .kg-fix .fix-choices {
  flex-direction: column;
  align-items: flex-start;
}
/* In a row the sentence and its two buttons wrap where the row has room — never past its edge. */
.fix-host .kg-fix {
  width: auto;
  max-width: none;
}
.order-grid td.note {
  font-size: 13px;
  color: var(--ink-2);
}
.order-grid td.note > span + .fix-host:not(:empty) {
  display: block;
  margin-top: 4px;
}
.order-list .fix-host {
  grid-column: 1 / -1;
}
.order-list .kg-fix {
  justify-content: flex-end;
  text-align: right;
}
/* In the table the field stands alone (72×44): −/+ belong to the phone's list rows. */
.kg.bare {
  grid-template-columns: 72px;
}
.kg.bare .kg-step {
  display: none;
}
.order-grid tr.off .copy-line {
  visibility: hidden;
}
.check-inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  cursor: pointer;
}
.check-inline input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--accent);
}
.grid-tools .jump {
  width: 180px;
  height: 36px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}
/* "Change to 20 kg" — a button that looks like one (review 0b: pale pills were not seen as buttons). */
.fix-pill {
  min-height: 30px;
  padding: 0 12px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  font: inherit;
  font-size: 13px;
  font-weight: 650;
  color: var(--accent-text);
  background: var(--surface);
  white-space: nowrap;
  cursor: pointer;
}
.fix-pill:hover {
  background: var(--accent-soft);
}
.fix-top:empty {
  display: none;
}

/* ---------- the order grid (plan 10.2: three layouts) ---------- */

/* clip, not hidden: the rounded edge clips, but the total bar and the floating scrollbar still stick to the screen. */
.grid-wrap {
  position: relative;
  border-radius: var(--r-l);
  overflow: clip;
}
.grid-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
}
.grid-tools .spacer {
  flex: 1;
}
.order-grid {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 14px;
}
.order-grid th {
  position: sticky;
  top: 0;
  z-index: 2;
  height: 48px;
  padding: 0 10px;
  text-align: left;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  background: color-mix(in srgb, var(--surface) 96%, var(--accent));
  border-bottom: 1px solid var(--line);
}
.order-grid td {
  height: 56px;
  padding: 0 10px;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
  vertical-align: middle;
}
.order-grid .num,
.order-grid th.num {
  text-align: right;
}
.order-grid tr.group td {
  height: 40px;
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: var(--glass-soft);
  box-shadow: inset 3px 0 0 var(--g, var(--accent));
}
.colour {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.swatch {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--sw, var(--line));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
}
.colour-no {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.colour-name {
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: opacity var(--fast) var(--ease);
}
.order-grid tr.off .colour-no,
.order-grid tr.off .colour-name,
.order-grid tr.off td {
  color: var(--ink-3);
}
.order-grid tr.on .colour-no,
.order-grid tr.on .colour-name {
  color: var(--ink);
  font-weight: 600;
}
/* The kg pill takes no room until the kg field has scrolled away (plan 10.2). */
.kg-pill {
  display: none;
  margin-left: auto;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 650;
  color: var(--accent-text);
  background: var(--accent-soft);
  white-space: nowrap;
}
.grid-wrap.scrolled tr.on .kg-pill {
  display: inline-block;
  animation: check-pop var(--mid) var(--spring);
}
/* Cells keep one line; the table is as wide as its columns — at 641–1023 px it then scrolls sideways. */
.order-grid th,
.order-grid td {
  white-space: nowrap;
}
.order-grid td.note {
  white-space: normal;
  min-width: 160px;
}
.order-grid th.num,
.order-grid td.num {
  width: 80px;
}
.order-grid td.lots {
  width: 72px;
}
/* Only 641–1023 px scrolls sideways; a wide screen keeps the table inside and lets the Note column wrap. */
@media (max-width: 1023px) {
  .grid-scroll .order-grid {
    min-width: max-content;
  }
}
.total-bar {
  position: sticky;
  bottom: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  min-height: 64px;
  padding: 10px 16px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  border-top: 1px solid var(--glass-line);
  font-size: 14px;
}
.total-bar .spacer {
  flex: 1;
}
.total-bar .fix-note {
  color: var(--warn);
  font-weight: 600;
}
/* In the app on a phone or tablet the tab bar sits at the bottom: the total bar and the scrollbar stop above it. */
@media (max-width: 899px) {
  .view .total-bar {
    bottom: calc(64px + env(safe-area-inset-bottom));
  }
  .view .h-scroll {
    bottom: calc(128px + env(safe-area-inset-bottom));
  }
}

/* 641–1023 px: the table scrolls sideways and the colour column closes as it goes (the portal's opdaterKolonne). */
.grid-scroll {
  overflow-x: auto;
  scrollbar-width: none;
}
.grid-scroll::-webkit-scrollbar {
  display: none;
}
.order-grid .sticky-col {
  position: sticky;
  left: 0;
  z-index: 1;
  width: var(--col-w, 210px);
  min-width: var(--col-w, 210px);
  max-width: var(--col-w, 210px);
  background: color-mix(in srgb, var(--surface) 96%, var(--accent));
}
.order-grid th.sticky-col {
  z-index: 3;
}
.grid-wrap.closing .order-grid .colour-name {
  opacity: var(--name-o, 1);
}
/* The column clips what no longer fits; once mostly closed it holds the number and the kg pill. */
.order-grid .sticky-col {
  overflow: hidden;
  text-overflow: ellipsis;
}
.grid-wrap.scrolled .order-grid .colour {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}
.grid-wrap.scrolled .order-grid .swatch,
.grid-wrap.scrolled .order-grid .colour-name {
  display: none;
}
.grid-wrap.scrolled .order-grid .kg-pill {
  margin-left: 0;
  padding: 0 6px;
  font-size: 10.5px;
}
.h-scroll {
  position: sticky;
  bottom: 64px;
  z-index: 4;
  height: 14px;
  margin: 0 12px;
  overflow-x: auto;
  overflow-y: hidden;
}
.h-scroll > div {
  height: 1px;
}
/* The table scrolls sideways at any width when it doesn't fit; grid.mjs shows the floating scrollbar only then. */
.h-scroll[hidden] {
  display: none;
}

/* ≤ 640 px: list rows (plan 10.2) — the page scrolls, nothing sideways. */
.order-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.order-list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: 6px 12px;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
}
.order-list li.group {
  min-height: 40px;
  font-size: 12px;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-2);
  background: var(--glass-soft);
  box-shadow: inset 3px 0 0 var(--g, var(--accent));
}
.order-list li.on .colour-no,
.order-list li.on .colour-name {
  color: var(--ink);
  font-weight: 600;
}
.order-list li.off .colour-no,
.order-list li.off .colour-name {
  color: var(--ink-3);
}

/* "Copy line" — 28 px to see, 44 to hit (plan 10.2). */
.copy-line {
  position: relative;
  width: 28px;
  height: 28px;
  display: inline-grid;
  place-items: center;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
.copy-line::before {
  content: "";
  position: absolute;
  inset: -8px;
}
.copy-line:hover {
  color: var(--accent);
  background: var(--accent-softer);
}
.copy-line.copied {
  color: var(--good);
}
.copied-note {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--good);
}

/* ---------- Home: "Needs your attention" (plan 10.2) ---------- */

.attention {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.attention li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: var(--r-m);
  animation: card-in var(--mid) var(--ease) backwards;
  animation-delay: calc(var(--i, 0) * 20ms);
}
@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}
.attention-head {
  margin: 0 0 10px;
  font-size: 17px;
  font-weight: 650;
}
.attention .why {
  font-size: 13.5px;
  color: var(--ink-2);
}
.attention .what {
  font-weight: 600;
}
.attention-more {
  margin-top: 8px;
}
@media (max-width: 640px) {
  .attention li {
    grid-template-columns: auto minmax(0, 1fr);
  }
  .attention li > .button {
    grid-column: 2;
    justify-self: start;
  }
}

/* ---------- chat (plan 10.2) ---------- */

.channel-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* A chat row: picture | name · time / the newest message, its own line / step and "2 new" (review 0b). */
.channel {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr) auto;
  grid-template-areas:
    "pic name time"
    "pic preview preview"
    "pic status status";
  column-gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 52px;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--r-s);
  font: inherit;
  text-align: left;
  color: inherit;
  background: transparent;
  cursor: pointer;
}
.channel:hover {
  background: var(--accent-softer);
}
.channel[aria-current="true"] {
  background: var(--accent-soft);
}
.channel > .avatar,
.channel > .channel-glyph {
  grid-area: pic;
  align-self: start;
}
.channel-glyph {
  width: 32px;
  height: 32px;
  border-radius: 10px;
}
.channel-name {
  grid-area: name;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 14px;
  font-weight: 520;
}
.channel.unread .channel-name {
  font-weight: 700;
}
.channel-name > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.channel-time {
  grid-area: time;
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  justify-self: end;
}
.channel-preview {
  grid-area: preview;
  min-width: 0;
  font-size: 13px;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.channel.unread .channel-preview {
  color: var(--ink);
}
.channel-status {
  grid-area: status;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}
.channel-status .status {
  height: 20px;
  padding: 0 8px 0 7px;
  font-size: 11.5px;
}
.channel-status .status::before {
  width: 6px;
  height: 6px;
}
.unread-pill {
  height: 20px;
  padding: 0 8px;
  display: inline-grid;
  place-items: center;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent);
}
/* VBM only: "Not seen by Samil yet" — in words. */
.unseen {
  font-size: 12px;
  color: var(--ink-2);
}

/* Over a conversation: the chat, its step and who reads along (review 0b). */
.chat-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
}
.chat-head > .icon-button {
  grid-row: span 2;
}
.chat-head > .channel-glyph {
  grid-row: span 2;
}
.chat-head:has(> .icon-button) {
  grid-template-columns: auto auto minmax(0, 1fr);
}
/* The way back to the list is only there where the list is its own screen (the shell's phone and tablet width). */
@media (min-width: 900px) {
  .chat-head > .icon-button {
    display: none;
  }
  .chat-head:has(> .icon-button) {
    grid-template-columns: auto minmax(0, 1fr);
  }
}
.chat-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 10px;
  min-width: 0;
  font-size: 15px;
}
.chat-members {
  font-size: 12.5px;
  color: var(--ink-2);
}

.conversation {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px;
  contain: content;
}
/* A day in the list (phase 2d: no longer sticky — a stuck pill lay over the words and over the next day's pill;
   one pill at the top says the day while the list moves, .day-float below). */
.day {
  align-self: center;
  height: 28px;
  display: inline-flex;
  align-items: center;
  padding: 0 12px;
  margin: 8px 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--surface) 92%, var(--accent));
  box-shadow: var(--shadow-s);
}
.new-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0;
  font-size: 12px;
  font-weight: 650;
  color: var(--accent);
}
.new-divider::before,
.new-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--accent);
}
.msg {
  display: grid;
  justify-items: start;
  gap: 3px;
  max-width: 68%;
}
.msg.mine {
  align-self: flex-end;
  justify-items: end;
}
@media (max-width: 640px) {
  .msg {
    max-width: 85%;
  }
}
.msg-who {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  padding: 0 4px;
}
.bubble {
  padding: 10px 14px;
  border-radius: 18px 18px 18px var(--tail);
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink);
  background: color-mix(in srgb, var(--surface) 92%, var(--accent));
  box-shadow: var(--shadow-s);
  overflow-wrap: anywhere;
}
.msg.mine .bubble {
  border-radius: 18px 18px var(--tail) 18px;
  background: color-mix(in srgb, var(--surface) 78%, var(--accent));
}
.msg.arrive .bubble {
  animation: bubble-in var(--slow) var(--spring);
}
@keyframes bubble-in {
  from {
    transform: translateY(8px);
    opacity: 0;
  }
}
.msg.sending .bubble {
  opacity: 0.6;
}
.msg.settle .bubble {
  transition: opacity var(--fast) var(--ease);
}
.msg.failed .bubble {
  box-shadow: inset 0 0 0 1.5px var(--bad);
}
.msg-meta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 4px;
  font-size: 11.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.msg-meta .bad {
  color: var(--bad);
  font-weight: 600;
}
.msg-meta .seen {
  color: var(--ink-2);
}
.msg-state {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
/* "Reply" and "Retry" stay one small line, but take a finger-sized hit (plan 10.6). */
.msg-meta .link-button {
  position: relative;
  min-height: 0;
  padding: 0 2px;
  font-size: inherit;
  font-weight: 600;
}
.msg-meta .link-button::before {
  content: "";
  position: absolute;
  inset: -12px -8px;
}
.to-mark {
  padding: 0 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 650;
  color: var(--accent-text);
  background: var(--accent-soft);
}
/* A quote is a button only when it can jump to the message it answers. */
.reply-quote {
  display: block;
  margin: 0 0 6px;
  padding: 4px 10px;
  border: 0;
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
button.reply-quote {
  cursor: pointer;
}
/* The message a quote jumped to, marked for a moment. */
.msg.jumped .bubble {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.reply-quote b {
  display: block;
  font-size: 12px;
  color: var(--accent-text);
}
.new-pill {
  position: sticky;
  bottom: 12px;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 13px;
  font-weight: 650;
  color: var(--accent-ink);
  background: var(--accent);
  box-shadow: var(--shadow);
  cursor: pointer;
}

.composer {
  display: grid;
  gap: 6px;
  padding: 8px 12px 12px;
}
.to-link {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 28px;
  padding: 0 4px;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.to-link b {
  color: var(--accent);
  font-weight: 650;
}
.to-link svg {
  color: var(--accent);
}
.to-link[aria-expanded="true"] svg {
  transform: rotate(180deg);
}
/* "Replying to Thandi" over the field, with a way out. */
.reply-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  padding: 4px 4px 4px 12px;
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  font-size: 13px;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.reply-bar > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.reply-bar b {
  margin-right: 6px;
  color: var(--ink);
}
.to-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.to-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 12px 0 4px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 13px;
  color: var(--ink-2);
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
  cursor: pointer;
}
.to-chip[aria-pressed="true"] {
  color: var(--accent-text);
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}
/* Over the chips: everyone reads it, the chosen also get a notification (plan 7.4). */
.to-hint {
  flex-basis: 100%;
  margin: 0 0 2px;
  font-size: 12.5px;
  color: var(--ink-2);
}
.to-group {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-right: 10px;
}
.to-side {
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* On a phone the search fills the screen: the field must look like one, not like a title (review 0b, round 3). */
@media (max-width: 640px) {
  .search-field input {
    height: 44px;
    margin: 8px 0;
    padding: 0 12px;
    border-radius: var(--r-s);
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--line);
  }
}
.compose-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: end;
  gap: 6px;
  padding: 4px;
  border-radius: 24px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  box-shadow: var(--shadow-s), inset 0 0 0 1px var(--glass-line);
}
.compose-row textarea {
  min-height: 40px;
  max-height: calc(6 * 1.45em + 20px);
  padding: 9px 4px;
  border: 0;
  outline: 0;
  resize: none;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  line-height: 1.45;
  field-sizing: content;
}
.icon-button {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
}
.icon-button:hover {
  color: var(--accent);
  background: var(--accent-softer);
}
/* Send is always there, with its word; it lights up when there is text (review 0b). */
.send-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 40px;
  padding: 0 14px 0 12px;
  border: 0;
  border-radius: 20px;
  font: inherit;
  font-size: 14px;
  font-weight: 650;
  color: var(--ink-2);
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
  cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.send-button.ready {
  color: var(--accent-ink);
  background: var(--accent);
  box-shadow: none;
}
.send-button.ready:hover {
  background: var(--accent-hover);
}
@media (pointer: coarse) {
  .send-button {
    height: 44px;
    border-radius: 22px;
  }
}
.mic-hint {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: 0;
  padding: 8px 8px 8px 12px;
  border-radius: var(--r-s);
  font-size: 13.5px;
  color: var(--ink);
  background: var(--warn-soft);
}
.mic-hint > svg {
  flex: none;
  margin-top: 2px;
}
.mic-hint p {
  flex: 1;
  min-width: 200px;
  margin: 0;
}

/* A voice message: recording replaces the field; Stop → listen → Send or Delete (never "let go = send"). */
.recorder {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 4px 6px 4px 14px;
  border-radius: 24px;
  background: var(--glass-strong);
  box-shadow: var(--shadow-s), inset 0 0 0 1px var(--glass-line);
}
.rec-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rec);
  animation: rec-pulse 1s var(--ease) infinite;
}
@keyframes rec-pulse {
  50% { opacity: 0.25; }
}
.rec-time {
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.levels {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 28px;
  overflow: hidden;
}
.levels i {
  flex: none;
  width: 3px;
  height: var(--l, 20%);
  border-radius: 2px;
  background: var(--accent);
  transition: height 90ms linear;
}
.rec-warn {
  grid-column: 1 / -1;
  font-size: 12.5px;
  color: var(--warn);
}
.recorder.preview {
  grid-template-columns: auto minmax(0, 1fr) auto auto;
}
/* A phone: the clip on its own line, Delete and Send under it — never over the waveform. */
@media (max-width: 480px) {
  .recorder.preview {
    grid-template-columns: minmax(0, 1fr) auto auto;
    padding: 6px 6px 6px 10px;
  }
  .recorder.preview .voice {
    grid-column: 1 / -1;
    min-width: 0;
  }
}
.voice {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  min-width: min(300px, 100%);
}
.voice-play {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  color: var(--accent-ink);
  background: var(--accent);
  cursor: pointer;
}
.wave {
  display: flex;
  align-items: center;
  gap: 2px;
  height: 32px;
  cursor: pointer;
  touch-action: none;
}
.wave i {
  flex: 1;
  min-width: 2px;
  height: var(--l, 30%);
  border-radius: 2px;
  background: var(--ink-3);
}
.wave i.played {
  background: var(--accent);
}
.voice-time {
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.thumb {
  display: block;
  width: clamp(160px, 40vw, 320px);
  aspect-ratio: 4 / 3;
  border: 0;
  padding: 0;
  border-radius: 14px;
  overflow: hidden;
  background: var(--glass-soft);
  cursor: zoom-in;
}
.thumb img,
.thumb svg {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.file-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 8px 10px 8px 12px;
  border-radius: var(--r-m);
  min-width: min(300px, 100%);
}
.file-name {
  display: flex;
  min-width: 0;
  font-size: 14px;
  font-weight: 600;
}
/* Middle-truncated: the start shrinks, the end ("…v3.pdf") always shows. */
.file-name .head {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-name .tail {
  flex: none;
  white-space: nowrap;
}
.file-meta {
  font-size: 12px;
  color: var(--ink-3);
}

/* ---------- the timeline (plan 10.3) ---------- */

.timeline {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  height: 420px;
  border-radius: var(--r-l);
  overflow: hidden;
}
/* Positioned: the rows measure where each month starts from here (timeline.mjs). */
.tl-scroll {
  position: relative;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  /* A month snaps to the very top (no padding): that is where the scrubber's name for it takes you. */
  scroll-snap-type: y proximity;
}
/* Phase 2e: the very bottom (the newest) is a resting place too, so a nearby month never pulls the list off it. */
.tl-scroll > .tl-item:last-child {
  scroll-snap-align: end;
}
.tl-scroll::-webkit-scrollbar {
  display: none;
}
.tl-month {
  position: sticky;
  top: 0;
  z-index: 1;
  height: 32px;
  display: flex;
  align-items: center;
  padding: 0 14px;
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--surface) 96%, var(--accent));
  scroll-snap-align: start;
}
/* Phase 2e: between December and January — a clear red line and the new year's number. Not sticky: it scrolls
   past under the month headings. */
.tl-year {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 30px;
  padding: 0 14px;
}
.tl-year-line {
  flex: 1;
  height: 2px;
  border-radius: 1px;
  background: var(--year-line);
}
.tl-year-no {
  font-size: 12.5px;
  font-weight: 750;
  letter-spacing: 0.04em;
  color: var(--year-line);
  font-variant-numeric: tabular-nums;
}
.tl-node {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  height: 56px;
  padding: 0 12px;
  border: 0;
  width: 100%;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.tl-node:hover {
  background: var(--accent-softer);
}
.tl-node.current {
  box-shadow: inset 3px 0 0 var(--accent);
}
.tl-text {
  display: grid;
  min-width: 0;
}
.tl-label {
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tl-sub {
  font-size: 12px;
  color: var(--ink-3);
}
.tl-time {
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.tl-stack {
  position: relative;
}
.tl-stack .more {
  position: absolute;
  right: -7px;
  bottom: -5px;
  min-width: 16px;
  padding: 0 4px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  text-align: center;
  color: var(--accent-ink);
  background: var(--accent);
}
.scrubber {
  position: relative;
  border-left: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 94%, var(--accent));
  cursor: pointer;
  touch-action: none;
}
/* A month's tick (phase 2d: finer — the 14 × 3 px dashes read as coarse in the rail's edge). */
.scrubber i {
  position: absolute;
  left: 50%;
  width: 8px;
  height: 2px;
  border-radius: 1px;
  transform: translateX(-50%);
  background: var(--ink-3);
  opacity: 0.45;
}
.scrubber b {
  position: absolute;
  left: 0;
  right: 0;
  font-size: 10.5px;
  font-weight: 650;
  line-height: 1.2;
  text-align: center;
  color: var(--ink-3);
  pointer-events: none;
}
/* Phase 2e: the turn of the year — red, wider and full strength, so it reads beside the months' ticks. */
.scrubber i.year {
  width: 18px;
  height: 2px;
  background: var(--year-line);
  opacity: 1;
}
/* The month the list is in now. */
.scrubber b.now {
  color: var(--ink);
  font-weight: 750;
}
.scrubber .thumb-bar {
  position: absolute;
  left: 6px;
  right: 6px;
  height: 24px;
  border-radius: 8px;
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* ---------- empty states, skeletons, the connection (plan 10.2) ---------- */

.empty-state {
  display: grid;
  justify-items: center;
  gap: 8px;
  max-width: 360px;
  margin: 0 auto;
  padding: 16px;
  text-align: center;
}
.empty-art {
  width: 160px;
  height: 120px;
  color: var(--ink-3);
  filter: drop-shadow(0 0 12px var(--halo));
}
.empty-art .fill,
.empty-art .face {
  fill: var(--accent-soft);
}
.empty-state h3 {
  margin: 4px 0 0;
  font-size: 17px;
  font-weight: 650;
}
.empty-state p {
  margin: 0;
  color: var(--ink-2);
  font-size: 14px;
}

/* Soft → strong, as the plan says — tinted with ink, so it shows on a plain surface as well as on glass. */
.skel {
  --skel-a: color-mix(in srgb, var(--ink) 7%, transparent);
  --skel-b: color-mix(in srgb, var(--ink) 13%, transparent);
  display: block;
  min-height: 10px;
  border-radius: 8px;
  background: linear-gradient(90deg, var(--skel-a) 0%, var(--skel-b) 50%, var(--skel-a) 100%) 0 0 / 200% 100%;
  animation: shimmer 1.2s linear infinite;
}
@keyframes shimmer {
  to {
    background-position: -200% 0;
  }
}
.skel-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  height: 52px;
  padding: 0 10px;
}
.skel-row .skel:first-child {
  width: 32px;
  height: 32px;
  border-radius: 50%;
}
.skel-lines {
  display: grid;
  gap: 6px;
}
.skel-bubbles {
  display: grid;
  gap: 10px;
  padding: 12px;
}
.skel-bubbles .skel {
  height: 40px;
  border-radius: 18px;
}
.skel-bubbles .skel:nth-child(odd) {
  width: 62%;
}
.skel-bubbles .skel:nth-child(even) {
  width: 48%;
  justify-self: end;
}

.net-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* Phase 2d: at least 32 px — on a phone the offline sentence takes two lines and must not spill out. */
  min-height: 32px;
  padding: 5px 12px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
  color: var(--ink);
  background: var(--warn-soft);
}

/* ---------- sheets, dialogs, search (plan 10.2) ---------- */

.sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 180;
  background: color-mix(in srgb, var(--ink) 28%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity var(--mid) var(--ease);
}
.sheet-backdrop.show {
  opacity: 1;
}
.sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 190;
  height: 90vh;
  height: 90dvh;
  display: flex;
  flex-direction: column;
  border-radius: 24px 24px 0 0;
  background: var(--surface);
  box-shadow: var(--shadow-l);
  transform: translateY(100%);
  transition: transform var(--slow) var(--spring);
  padding-bottom: env(safe-area-inset-bottom);
}
.sheet.show {
  transform: translateY(var(--drag, 0px));
}
.sheet.dragging {
  transition: none;
}
.sheet-handle {
  flex: none;
  height: 28px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  cursor: grab;
  touch-action: none;
}
.sheet-handle::before {
  content: "";
  width: 40px;
  height: 5px;
  border-radius: 3px;
  background: var(--line);
}
.sheet-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px 10px;
}
.sheet-head h3 {
  flex: 1;
  margin: 0;
  font-size: 17px;
  font-weight: 650;
}
.sheet-body {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 16px 16px;
}

dialog.dialog {
  width: min(460px, calc(100vw - 32px));
  padding: 22px;
  border: 0;
  border-radius: var(--r-xl);
  color: var(--ink);
  background: var(--surface);
  box-shadow: var(--shadow-l), inset 0 0 0 1px var(--glass-edge);
}
dialog.dialog::backdrop {
  background: color-mix(in srgb, var(--ink) 30%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
dialog.dialog[open] {
  animation: dialog-in var(--mid) var(--spring);
}
@keyframes dialog-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.98);
  }
}
.dialog h3 {
  margin: 0 0 6px;
  font-size: 19px;
  font-weight: 650;
}
.dialog p {
  margin: 0 0 18px;
  color: var(--ink-2);
}
.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
}

.search {
  position: fixed;
  top: 12vh;
  left: 50%;
  z-index: 210;
  width: min(640px, calc(100vw - 32px));
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  transform: translateX(-50%);
  border-radius: var(--r-xl);
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  box-shadow: var(--shadow-l), inset 0 0 0 1px var(--glass-edge);
  overflow: hidden;
}
.search-field {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px;
  border-bottom: 1px solid var(--line);
}
.search-field input {
  flex: 1;
  height: 56px;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 17px;
}
.search-close {
  flex: none;
}
/* The search in the top bar: shaped like a field, so it reads as "search here" (review 0b). */
.search-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 36px;
  min-width: 200px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 14px;
  color: var(--ink-2);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  cursor: pointer;
}
.search-button:hover {
  box-shadow: inset 0 0 0 1px var(--accent);
}
@media (max-width: 640px) {
  .search-button {
    min-width: 0;
    width: 44px;
    height: 44px;
    padding: 0;
    justify-content: center;
  }
  .search-button > span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
}
.search-results {
  overflow-y: auto;
  padding: 6px;
}
.search-group h4 {
  margin: 10px 10px 4px;
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.search-hit {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--r-s);
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.search-hit small {
  display: block;
  color: var(--ink-3);
  font-size: 12.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.search-hit mark {
  color: inherit;
  background: var(--accent-soft);
  border-radius: 3px;
  padding: 0 1px;
}
.search-hit[aria-selected="true"],
.search-hit:hover {
  background: var(--accent-soft);
}
.search-more {
  margin: 0 10px 6px;
  font-size: 13px;
}
@media (max-width: 640px) {
  .search {
    top: 0;
    left: 0;
    width: 100vw;
    max-height: none;
    height: 100dvh;
    transform: none;
    border-radius: 0;
  }
}

/* Toast with "Undo": 6 s, with a bar that counts down (plan 10.2). */
/* A plain toast while one with "Undo" is up goes one row higher, so neither covers the other. */
.toast.show.lifted {
  transform: translate(-50%, -60px);
}
.toast .toast-undo {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.toast-bar {
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 4px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  opacity: 0.5;
  transform-origin: left;
  animation: countdown var(--ms, 6000ms) linear forwards;
}
@keyframes countdown {
  to {
    transform: scaleX(0);
  }
}

/* ---------- the goat (plan 10.4: a blink or an ear, about once a minute) ---------- */

.goat {
  display: block;
  color: currentColor;
}
.goat .eye {
  transform-box: fill-box;
  transform-origin: center;
}
.goat.blink .eye {
  animation: goat-blink 300ms var(--ease);
}
@keyframes goat-blink {
  50% {
    transform: scaleY(0.1);
  }
}
.goat .ear {
  transform-box: fill-box;
  transform-origin: 90% 20%;
}
.goat.ear-flick .ear {
  animation: goat-ear 300ms var(--ease);
}
@keyframes goat-ear {
  50% {
    transform: rotate(-14deg);
  }
}
.goat-tile {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  color: var(--paa-accent);
  background: linear-gradient(160deg, var(--maerke-fra), var(--maerke-til));
  box-shadow: 0 6px 18px var(--accent-gloed);
}

/* ---------- avatars at their four sizes (plan 10.2: 24/32/40/64) ---------- */

.avatar-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

/* ---------- touch, motion, colours (plan 10.6) ---------- */

@media (pointer: coarse) {
  .kg {
    grid-template-columns: 44px 72px 44px;
  }
  .kg-step {
    width: 44px;
    height: 44px;
  }
  /* Every control at least 44 px on touch (plan 10.6) — the small buttons too (review 0b measured 36–40). */
  .button.small,
  .fix-pill,
  .to-chip,
  .to-link,
  .search-button,
  .grid-tools .jump,
  .check-inline,
  .toast .toast-undo {
    min-height: 44px;
  }
  .toast .toast-undo {
    padding: 0 10px;
  }
  .icon-button {
    width: 44px;
    height: 44px;
  }
  .channel {
    min-height: 56px;
  }
  .step-node::before {
    content: "";
    position: absolute;
    inset: -8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .skel {
    background: var(--skel-a);
  }
  .rec-dot {
    opacity: 1;
  }
}

/* ---------- phase 1a: groups, units, priority, note, the picture, the pages ---------- */

/* A group's row: fold button, the PDF's heading, the lot size, what is typed in. */
.order-grid td.group-cell {
  padding: 0;
}
/* The group's content sticks to the scroller's left edge, so a heading never hides under the closed colour column. */
.group-row {
  position: sticky;
  left: 0;
  display: flex;
  align-items: center;
  gap: 4px 12px;
  flex-wrap: wrap;
  width: max-content;
  max-width: min(100%, calc(100vw - 120px));
  padding: 4px 10px 4px 6px;
}
.order-grid tr.group td,
.order-list li.group {
  text-transform: none;
  letter-spacing: 0;
}
.order-list li.group {
  grid-template-columns: auto minmax(0, 1fr);
  padding: 6px 12px 6px 8px;
}
.fold {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 0 8px 0 4px;
  border: 0;
  border-radius: var(--r-s);
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.fold:hover {
  background: var(--accent-softer);
}
.fold svg {
  transition: transform var(--fast) var(--ease);
}
.group.folded .fold svg {
  transform: rotate(-90deg);
}
.group-head {
  display: flex;
  align-items: center;
  gap: 6px 14px;
  flex-wrap: wrap;
  min-width: 0;
}
.group-title {
  font-size: 12.5px;
  color: var(--ink-2);
  white-space: normal;
}
.group-title b {
  color: var(--ink);
}
.group-meta {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  white-space: nowrap;
}
.group-sum {
  font-weight: 650;
  color: var(--ink-2);
}
/* "Kg | Balls" — a pressed pair, the chosen one filled. */
.unit-pick {
  display: inline-flex;
  padding: 2px;
  border-radius: 999px;
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.unit {
  min-height: 28px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 12.5px;
  font-weight: 650;
  cursor: pointer;
}
.unit.on {
  background: var(--surface);
  color: var(--accent-text);
  box-shadow: var(--shadow-s);
}
.order-fields .unit-pick {
  justify-self: start;
  margin-top: 4px;
}
@media (pointer: coarse) {
  .unit,
  .fold {
    min-height: 44px;
  }
}

/* The colour cell: number, name, marks — and on a touch screen the English name small under it. */
.colour-text {
  display: grid;
  min-width: 0;
}
.colour-line {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
.colour-marks {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin-top: 2px;
}
.colour-marks .tag {
  margin-left: 0;
}
.colour-en {
  display: none;
  font-size: 11.5px;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.grid-wrap.touch .colour-en {
  display: block;
}
.colour:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}
.swatch.undyed {
  background: repeating-linear-gradient(45deg, #efe9dc 0 4px, #e2d8c4 4px 8px);
}
.colour.ecru .colour-no {
  font-weight: 650;
}
.tag {
  white-space: nowrap;
}
.tag-hand {
  background: color-mix(in srgb, var(--garn-boucle) 16%, transparent);
  color: color-mix(in srgb, var(--garn-boucle) 75%, var(--ink));
}
.tag-off {
  background: var(--glass-soft);
  color: var(--ink-3);
  box-shadow: inset 0 0 0 1px var(--line);
}
.tag-warn {
  background: var(--warn-soft);
  color: color-mix(in srgb, var(--warn) 70%, var(--ink));
}

/* The picture on hover or press-and-hold (the portal's data-billede): 120 px, the number, the English name. */
.colour-peek {
  position: fixed;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px;
  border-radius: var(--r-m);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-l), inset 0 0 0 1px var(--line);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--fast) var(--ease);
}
.colour-peek.show {
  opacity: 1;
}
.colour-peek img,
.peek-swatch {
  display: block;
  width: 120px;
  height: 120px;
  border-radius: 10px;
  object-fit: cover;
  background: var(--sw, var(--line));
}
.peek-swatch.undyed {
  background: repeating-linear-gradient(45deg, #efe9dc 0 8px, #e2d8c4 8px 16px);
}
.peek-text {
  display: grid;
  gap: 2px;
  font-size: 14px;
  max-width: 180px;
}
.peek-text small {
  color: var(--ink-3);
}

/* Priority, note, the shared lot, the lots and the other unit in the table. */
.prio {
  min-height: 36px;
  padding: 0 8px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}
.note-field {
  width: 100%;
  min-width: 140px;
  min-height: 36px;
  padding: 0 10px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
}
.prio:disabled,
.note-field:disabled {
  opacity: 0.45;
}
.order-grid td.prio-cell {
  width: 72px;
}
.order-grid td.other-unit,
.order-grid td.extra {
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.order-grid tr.off td.other-unit,
.order-grid tr.off td.extra {
  color: var(--ink-3);
}
.lots-text {
  white-space: nowrap;
}
.share-lot {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 4px;
  min-height: 26px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.share-lot[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-text);
}
.share-lot[hidden] {
  display: none;
}
.order-grid td.lots {
  width: auto;
}
.kg-text {
  font-variant-numeric: tabular-nums;
}
.order-grid tr.off .kg-text {
  font-weight: 400;
  color: var(--ink-3);
}

/* The phone's list rows: a second line with lots and balls, priority and note under an ordered row. */
/* The phone's group heading wraps instead of being cut off at the edge. */
.order-list .group-meta,
.order-list .group-title {
  white-space: normal;
}
.order-list .row-more {
  grid-column: 1 / -1;
  font-size: 12.5px;
  color: var(--ink-3);
}
.order-list li.off .row-more {
  display: none;
}
.order-list .row-fields {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.order-list li.off .row-fields {
  display: none;
}
.row-prio {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-2);
}
.order-list .note-field {
  flex: 1 1 160px;
}
.order-list .kg-text {
  font-size: 16px;
}

/* The bar: the save state next to the totals. */
.save-state {
  font-size: 13px;
  color: var(--ink-3);
}
.save-state.ok {
  color: var(--good);
}
.save-state.bad {
  color: var(--bad);
  font-weight: 600;
}
.save-state.pending {
  color: var(--ink-3);
}
.total-text b {
  font-size: 16px;
}

/* ---------- the pages: the list, the head, the sections ---------- */

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px 20px;
  flex-wrap: wrap;
  margin: 0 0 16px;
}
.page-head h2,
.order-head h2 {
  margin: 0 0 4px;
  font-size: clamp(22px, 2.6vw, 28px);
  font-weight: 650;
}
.page-head p,
.order-head p {
  margin: 0;
}
.order-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}
.order-card {
  border-radius: var(--r-l);
}
.order-card-link {
  display: grid;
  gap: 6px;
  padding: 16px 18px;
  border-radius: var(--r-l);
  color: inherit;
  text-decoration: none;
}
.order-card-link:hover {
  background: var(--accent-softer);
}
.order-card-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.order-card-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}
.order-no {
  font-size: 18px;
  font-weight: 700;
}
.order-kg {
  font-weight: 600;
  color: var(--ink-2);
}
.order-card-meta,
.order-card-note {
  font-size: 13.5px;
  color: var(--ink-2);
}
.order-card-note {
  color: var(--ink-3);
}
.order-head {
  margin: 0 0 16px;
}
.order-head-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px 20px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.order-head-row h2 {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.order-head-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.order-head .how {
  margin: 0 0 12px;
  font-size: 14px;
}
.order-fields {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 12px 20px;
  margin-bottom: 16px;
}
@media (max-width: 640px) {
  .order-fields {
    grid-template-columns: 1fr;
  }
}
.notice.editing {
  --c: var(--st-change);
}
.notice[hidden] {
  display: none;
}
.order-note {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-radius: var(--r-m);
  background: var(--glass-soft);
  font-size: 14px;
}
.order-section {
  margin: 20px 0 0;
}
.order-section > h3 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 650;
}
.order-section > h3 svg {
  color: var(--accent);
}
.order-section > p.muted {
  margin: 0 0 12px;
  font-size: 14px;
}
.doc-slots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
}
.grid-source-note {
  margin: 10px 0 0;
  font-size: 13px;
}
.stepper-wrap {
  margin-bottom: 8px;
}

/* ---------- the order sheet as a page to print ---------- */

.print-page {
  max-width: 1000px;
  margin: 0 auto;
  padding: 24px clamp(16px, 3vw, 36px) 64px;
}
.print-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.print-head h1 {
  margin: 0 0 4px;
  font-size: 26px;
  font-weight: 700;
}
.print-head p {
  margin: 2px 0;
}
.print-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.print-group {
  margin: 0 0 22px;
  break-inside: avoid;
}
.print-group h2 {
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-2);
}
.print-group h2 b {
  color: var(--ink);
}
.print-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.print-table th,
.print-table td {
  padding: 4px 8px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.print-table th {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-3);
}
.print-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.print-table tr.on td {
  font-weight: 650;
  color: var(--ink);
}
.print-table tr.off td {
  color: var(--ink-3);
}
.print-table td.note {
  white-space: normal;
}
.print-foot {
  font-size: 12.5px;
}
@media print {
  .print-actions,
  .backdrop,
  .toast {
    display: none !important;
  }
  body,
  .print-page {
    background: #fff;
    color: #000;
    padding: 0;
    max-width: none;
  }
  .print-table tr.on td {
    color: var(--print-blaek, #000);
  }
  .print-table tr.off td {
    color: #777;
  }
  .print-table th,
  .print-table td {
    border-bottom-color: #ccc;
  }
  .print-group h2 b,
  .print-head h1 {
    color: #000;
  }
}

@media (forced-colors: active) {
  .status,
  .doc-tile,
  .journey,
  .kg input,
  .fix-pill,
  .to-chip,
  .unread-pill,
  .new-pill,
  .doc-slot,
  .send-button,
  .search-button,
  .slot-steps > li::before {
    border: 1px solid CanvasText;
  }
  .status::before,
  .journey::before {
    forced-color-adjust: none;
    background: CanvasText;
  }
  .step.done .step-node,
  .step.now .step-node {
    outline: 2px solid Highlight;
  }
  .wave i.played,
  .levels i {
    background: Highlight;
  }
}

/* ---------- phase 1b: the order page's steps — confirmation, change, shipments, release ---------- */

.order-page { display: grid; gap: 4px; }
.order-fresh {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 0 0 12px; padding: 10px 14px; border-radius: var(--r-l);
  background: var(--accent-soft); color: var(--ink);
}
.order-fresh[hidden] { display: none; }
.step-skip { margin: 6px 0 0; font-size: 13.5px; }
.slot-group { margin: 18px 0 8px; font-size: 14px; font-weight: 650; }
.slot-more { margin: 8px 0 0; font-size: 13.5px; color: var(--ink-2); display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }

/* An order confirmation per sales order: the file, the date, and its lines — differences marked. */
.so-card { grid-template-columns: auto minmax(0, 1fr); background: var(--glass-soft); box-shadow: inset 0 0 0 1px var(--line); }
.so-card > .slot-actions { grid-column: 1 / -1; }
.so-ready { display: flex; flex-wrap: wrap; align-items: end; gap: 8px; }
.so-summary { display: none; }
.confirm-table { width: 100%; margin-top: 10px; border-collapse: collapse; font-size: 13.5px; }
.confirm-table th { text-align: left; font-weight: 600; color: var(--ink-2); padding: 6px 8px; border-bottom: 1px solid var(--line); }
.confirm-table td { padding: 6px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.confirm-table td.num, .confirm-table th:nth-child(2), .confirm-table th:nth-child(3), .confirm-table th:nth-child(5) { text-align: right; white-space: nowrap; }
.confirm-table tr.differs td { background: color-mix(in srgb, var(--surface) 90%, var(--st-change)); }
.confirm-table .was { display: block; color: var(--ink-3); font-size: 12px; }
.price-tag { display: inline-block; margin-top: 4px; font-size: 11.5px; white-space: nowrap; }
@media (max-width: 640px) {
  /* A phone shows the lines that differ, and how many are as ordered. */
  .so-summary { display: block; }
  .confirm-table thead, .confirm-table tr.same { display: none; }
  .confirm-table tr { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; padding: 8px 0; border-bottom: 1px solid var(--line); }
  .confirm-table td { border: 0; padding: 0; }
  .confirm-table td:first-child { grid-column: 1 / -1; font-weight: 600; }
}

/* The confirmation form's fourth step: "All 9 lines as ordered", or the lines one by one. */
.confirm-step { display: grid; gap: 8px; }
.confirm-list { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 10px; }
.confirm-list[hidden] { display: none; }
.confirm-line { padding: 10px 12px; border-radius: var(--r-m, 10px); box-shadow: inset 0 0 0 1px var(--line); background: var(--surface); }
.confirm-line.off { opacity: 0.6; }
.confirm-fields { display: flex; flex-wrap: wrap; align-items: end; gap: 8px 14px; margin-top: 8px; }
.confirm-fields .field input[type="text"] { width: 7.5em; }
.confirm-fields .confirm-note { flex: 1 1 12em; }
.confirm-fields .confirm-note input { width: 100%; }
.check-inline input[type="checkbox"], .check-inline input[type="radio"] { width: 20px; height: 20px; }
@media (pointer: coarse) {
  .check-inline { min-height: 44px; }
}

/* Changes: what was answered, with Samil's comment. */
.change-history { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 8px; font-size: 13.5px; }
.change-comment { display: block; margin: 4px 0 0 2px; color: var(--ink-2); font-style: italic; }
.enter-answer { margin-top: 10px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.change-editor { display: grid; gap: 12px; }
.change-editor textarea { width: 100%; min-height: 4em; }

/* Shipments: the line, what it carries, and its own documents in order. */
.shipment-card { display: grid; gap: 8px; padding: 12px 0 16px; border-bottom: 1px solid var(--line); }
.shipment-card:last-child { border-bottom: 0; }
.shipment-lines { margin: 0; font-size: 13px; }
.invoice-wrap { display: grid; gap: 4px; }
.invoice-facts, .invoice-pay { margin: 0 4px; font-size: 13px; color: var(--ink-2); }

/* VBM's release for shipment: per line air, sea or hold. */
.release { display: grid; gap: 10px; padding: 16px; border-radius: var(--r-l); outline: 1.5px dashed var(--accent); outline-offset: -1.5px; background: color-mix(in srgb, var(--surface) 94%, var(--accent)); }
.release h4 { margin: 0; }
.release-all { display: flex; flex-wrap: wrap; gap: 6px; }
.release-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.release-line { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 6px 14px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.release-modes { display: flex; gap: 14px; }

/* ---------- phase 2a: the chat page — three columns, push navigation, system lines, deleted, "…" ---------- */

/* The chat fills the screen under the top bar: the list and the conversation scroll, the page does not. */
body[data-area="chat"] {
  overflow: hidden;
}
body[data-area="chat"] .main {
  height: 100vh;
  height: 100dvh;
}
body[data-area="chat"] .view {
  flex: 1 1 auto;
  min-height: 0;
  max-width: none;
  display: flex;
  padding: 16px clamp(12px, 2vw, 24px);
}
/* Channels 272 px · the conversation at least 520 px · the timeline's rail (0 until phase 2b, plan 10.2). */
.chat-shell {
  --rail: 0px;
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: 272px minmax(520px, 1fr) var(--rail);
  border-radius: var(--r-l);
  overflow: hidden;
}
.chat-list {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 8px;
  border-right: 1px solid var(--line);
}
.chat-list .channel-item + .channel-item {
  margin-top: 2px;
}
.chat-rail {
  min-width: 0;
}
.chat-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.chat-pane.fade-in {
  animation: chat-fade var(--fast) var(--ease);
}
@keyframes chat-fade {
  from {
    opacity: 0;
  }
}
.chat-title a {
  color: inherit;
}
.chat-scroll {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.chat-scroll > .conversation {
  flex: 1 0 auto;
  justify-content: flex-end;
}
.chat-older {
  align-self: center;
  margin-top: 10px;
}
.chat-empty {
  margin: auto 0;
  padding: 24px 0;
}
.chat-foot {
  border-top: 1px solid var(--line);
}
.chat-viewing {
  margin: 0;
  padding: 14px 16px;
  font-size: 13.5px;
  color: var(--ink-2);
  text-align: center;
}
/* Words only in 2a (no clip, no microphone): the field gets the room the clip had. */
.compose-row.words-only {
  grid-template-columns: minmax(0, 1fr) auto;
  padding-left: 14px;
}
/* A message's own words: its line breaks, and a long address that wraps. */
.msg-text {
  white-space: pre-wrap;
}
.msg-text a {
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.msg.mine .msg-text a {
  color: inherit;
}

/* A system line ("Dyeing has started"): centred, no bubble, no "Seen by" (svar 10). */
.msg.system {
  align-self: center;
  max-width: min(90%, 520px);
  justify-items: center;
  gap: 1px;
  margin: 4px 0;
  text-align: center;
}
.system-text {
  font-size: 13px;
  font-weight: 560;
  color: var(--ink-2);
}
/* Deleted: "Message deleted" in italics, quiet — never who (svar 11). */
.msg.deleted .bubble {
  font-style: italic;
  font-size: 14px;
  color: var(--ink-3);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--line);
}
/* The message a quote jumped to: marked, and the mark fades over 1.2 s (plan 10.3). */
.conversation .msg.jumped .bubble {
  outline: 2px solid transparent;
  animation: jumped 1.2s var(--ease);
}
@keyframes jumped {
  from,
  30% {
    outline-color: var(--accent);
  }
}
/* "…" next to your own message: Delete lives behind it (and press-and-hold on a phone) — never a link on every bubble. */
/* The line under a bubble wraps by its parts ("Seen by …" whole on its own line), at the bubble's side. */
.chat-scroll .msg-meta {
  flex-wrap: wrap;
  row-gap: 2px;
}
.chat-scroll .msg.mine .msg-meta {
  justify-content: flex-end;
}
.msg-more {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
}
.msg-more::before {
  content: "";
  position: absolute;
  inset: -12px -10px;
}
.msg-more:hover,
.msg-more[aria-expanded="true"] {
  color: var(--accent);
  background: var(--accent-softer);
}
.menu-list button.danger {
  color: var(--bad);
}
/* "Done" closes the "To:" choice. */
.to-done {
  margin-left: auto;
}
/* The order page's way into its chat. */
.order-chat {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin: 0;
}

/* The unread number on Chat, in the column and the tab bar (plan 2a). */
.rail-link,
.tab {
  position: relative;
}
.nav-badge {
  position: absolute;
  top: 2px;
  left: calc(50% + 6px);
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: inline-grid;
  place-items: center;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--accent-ink);
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--surface);
}
.nav-badge[hidden] {
  display: none;
}

/* Below 900 px: the list and the conversation are two screens (/chat → /chat/<id>), and the tab bar steps aside in a conversation. */
@media (max-width: 899px) {
  body[data-area="chat"] .view {
    padding: 0 0 calc(64px + env(safe-area-inset-bottom));
  }
  body[data-area="chat"][data-conversation] .view {
    padding-bottom: env(safe-area-inset-bottom);
  }
  body[data-conversation] nav.tab-bar {
    display: none;
  }
  .chat-shell {
    grid-template-columns: minmax(0, 1fr);
    border-radius: 0;
    box-shadow: none;
  }
  .chat-shell:not([data-open]) .chat-pane,
  .chat-shell[data-open] .chat-list,
  .chat-rail {
    display: none;
  }
  .chat-list {
    border-right: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat-pane.fade-in {
    animation: none;
  }
  /* The mark still shows — it just doesn't fade. */
  .conversation .msg.jumped .bubble {
    animation: none;
    outline-color: var(--accent);
  }
}
@media (forced-colors: active) {
  .nav-badge {
    border: 1px solid CanvasText;
  }
  .msg.deleted .bubble,
  .msg.system .system-text {
    color: GrayText;
  }
}

/* ---------- phase 2b: files — the composer's "+", files in a bubble, the drop frame, the viewer, the timeline rail, the Files page ---------- */

/* The composer with "+" and no microphone yet (2c brings it). */
.compose-row.no-mic {
  grid-template-columns: auto minmax(0, 1fr) auto;
}
.attach-button[aria-expanded="true"] {
  color: var(--accent);
  background: var(--accent-softer);
}
/* What goes with the next message: a chip each, × to take it out. */
.file-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.file-chips[hidden] {
  display: none;
}
.file-chip {
  display: inline-grid;
  grid-template-columns: 32px minmax(0, auto) auto 32px;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  min-height: 40px;
  padding: 3px 0 3px 4px;
  border-radius: 12px;
  font-size: 13px;
  color: var(--ink);
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.file-chip img {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  object-fit: cover;
}
.file-chip .doc-tile {
  width: 32px;
  height: 32px;
}
.file-chip-name {
  max-width: 16em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}
.file-chip small {
  color: var(--ink-3);
  font-size: 12px;
  white-space: nowrap;
}
.file-chip-x {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
}
.file-chip-x:hover {
  color: var(--bad);
  background: var(--bad-soft);
}
@media (pointer: coarse) {
  .file-chip {
    grid-template-columns: 32px minmax(0, auto) auto 44px;
  }
  .file-chip-x {
    width: 44px;
    height: 44px;
  }
}

/* In a bubble: the words, the photos (one large, more in a grid), the other files as cards. */
.msg-files {
  position: relative;
  display: grid;
  gap: 8px;
  min-width: 0;
}
.msg-pics {
  display: grid;
  gap: 4px;
  width: clamp(160px, 52vw, 320px);
}
.msg-pics .thumb {
  width: 100%;
  max-height: 420px;
  aspect-ratio: 4 / 3;
  border-radius: 12px;
}
.msg-pics.many {
  grid-template-columns: 1fr 1fr;
}
.msg-pics.many .thumb {
  aspect-ratio: 1 / 1 !important;
}
.thumb .thumb-none svg {
  width: 28px;
  height: 28px;
}
.thumb-none {
  width: 100%;
  height: 100%;
  min-height: 96px;
  display: grid;
  place-items: center;
  color: var(--ink-3);
  background: var(--glass-soft);
}
.msg-files .file-card {
  min-width: min(280px, 100%);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  box-shadow: inset 0 0 0 1px var(--line);
}
.file-removed {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 13.5px;
  font-style: italic;
  color: var(--ink-3);
}
/* The upload: 3 px at the bubble's foot ("Sending… 64 %" says the same in words). */
.up-bar {
  display: block;
  height: 3px;
  border-radius: 2px;
  overflow: hidden;
  background: var(--line);
}
.up-bar i {
  display: block;
  height: 100%;
  width: var(--p, 0%);
  background: var(--accent);
  transition: width var(--mid) var(--ease);
}

/* Lit from the timeline: a soft accent behind the message that fades over 1.2 s (plan 10.3). */
.conversation .msg.lit .bubble,
.conversation .msg.system.lit {
  animation: lit 1.2s var(--ease);
}
.conversation .msg.system.lit {
  border-radius: 12px;
}
@keyframes lit {
  from,
  25% {
    background: var(--accent-soft);
  }
}

/* The drop frame over the conversation (plan 10.4): 2 px dashed accent and where the files will go. */
.chat-pane {
  position: relative;
}
.drop-zone {
  position: absolute;
  inset: 8px;
  z-index: 5;
  display: grid;
  place-items: center;
  border: 2px dashed var(--accent);
  border-radius: var(--r-l);
  background: color-mix(in srgb, var(--surface) 86%, var(--accent));
  pointer-events: none;
}
.drop-zone[hidden] {
  display: none;
}
.drop-zone p {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: 16px;
  font-weight: 650;
  color: var(--accent-text);
}

/* "Files (12)" in the head — where the rail has no room beside the chat. */
.chat-head.with-files {
  grid-template-columns: auto minmax(0, 1fr) auto;
}
.chat-head.with-files:has(> .icon-button) {
  grid-template-columns: auto auto minmax(0, 1fr) auto;
}
@media (min-width: 900px) {
  .chat-head.with-files:has(> .icon-button) {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }
}
.chat-files {
  grid-column: -2;
  grid-row: 1;
  white-space: nowrap;
}
/* Who reads along takes the whole width under the title and the button (a phone has little room). */
.chat-head.with-files .chat-members {
  grid-column: 2 / -1;
}
.chat-head.with-files:has(> .icon-button) .chat-members {
  grid-column: 3 / -1;
}
@media (min-width: 900px) {
  .chat-head.with-files:has(> .icon-button) .chat-members {
    grid-column: 2 / -1;
  }
}
.chat-files[hidden] {
  display: none;
}

/* The rail: none below 1180 px, a 44 px strip that unfolds from 1180 px, open (288 px) from 1440 px (plan 10.2). */
.chat-rail {
  position: relative;
  min-height: 0;
  display: none;
  border-left: 1px solid var(--line);
}
.rail-strip {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 14px 0;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  cursor: pointer;
}
.rail-strip:hover {
  color: var(--accent);
  background: var(--accent-softer);
}
.rail-strip-word {
  writing-mode: vertical-rl;
  font-size: 12.5px;
  font-weight: 650;
  letter-spacing: 0.04em;
}
.rail-strip-count:not(:empty) {
  min-width: 22px;
  padding: 1px 5px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
  background: var(--accent-soft);
}
.rail-panel {
  display: none;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}
.rail-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 48px;
  padding: 4px 6px 4px 14px;
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
}
.rail-head b {
  flex: 1;
  font-weight: 650;
}
.rail-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.rail-body > .timeline {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
  border-radius: 0;
  box-shadow: none;
  background: transparent;
}
.rail-none {
  margin: 0;
  padding: 16px 14px;
  font-size: 13px;
  color: var(--ink-2);
}
@media (min-width: 1180px) {
  .chat-shell {
    --rail: 44px;
  }
  .chat-rail {
    display: block;
  }
  .chat-head .chat-files {
    display: none;
  }
  /* Unfolded: 288 px over the conversation's right edge, until it is folded again. */
  .chat-shell[data-rail-open] .rail-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 6;
    display: flex;
    width: 288px;
    background: var(--surface);
    box-shadow: var(--shadow-l);
  }
}
@media (min-width: 1440px) {
  .chat-shell {
    --rail: 288px;
  }
  .rail-strip,
  .rail-fold {
    display: none;
  }
  .rail-panel,
  .chat-shell[data-rail-open] .rail-panel {
    position: static;
    display: flex;
    width: auto;
    background: transparent;
    box-shadow: none;
  }
}

/* The node for the message in the chat's middle: an accent dot that comes in 160 ms (plan 10.3). */
.tl-node {
  position: relative;
}
.tl-node.current {
  box-shadow: none;
}
.tl-node::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.tl-node.current::before {
  opacity: 1;
  transform: none;
}

/* The timeline as a sheet: from the bottom on a phone, at the side on a wider screen. */
.sheet.tl-sheet .sheet-body {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}
.sheet.tl-sheet .timeline {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
  border-radius: 0;
  box-shadow: none;
  background: transparent;
}
@media (min-width: 900px) {
  .sheet.tl-sheet {
    left: auto;
    top: 0;
    width: min(380px, 92vw);
    height: 100%;
    border-radius: 24px 0 0 24px;
    transform: translateX(100%);
  }
  .sheet.tl-sheet.show {
    transform: none;
  }
  .sheet.tl-sheet .sheet-handle {
    display: none;
  }
  .sheet.tl-sheet .sheet-head {
    padding-top: 14px;
  }
}

/* ---------- the viewer ---------- */

.viewer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: color-mix(in srgb, #000 72%, transparent);
}
.viewer {
  position: fixed;
  inset: 16px;
  z-index: 210;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: var(--shadow-l);
  overflow: hidden;
}
.viewer-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 8px;
  padding: 8px 8px 8px 16px;
  border-bottom: 1px solid var(--line);
}
.viewer-name {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
}
.viewer-title {
  margin: 0;
  font-size: 15px;
  font-weight: 650;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.viewer-count {
  flex: none;
  font-size: 12.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.viewer-actions {
  display: flex;
  gap: 6px;
}
.viewer-actions [hidden] {
  display: none;
}
.viewer-body {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  min-height: 0;
  background: color-mix(in srgb, var(--surface) 90%, var(--ink));
}
.viewer-stage {
  grid-column: 2;
  grid-row: 1;
  display: grid;
  place-items: center;
  height: 100%;
  min-height: 0;
  min-width: 0;
  padding: 12px;
}
.viewer-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 6px;
}
.viewer-pdf {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 6px;
  background: #fff;
}
.viewer-skel {
  width: min(480px, 80%);
  height: 60%;
  border-radius: 12px;
}
.viewer-plain {
  display: grid;
  justify-items: center;
  gap: 10px;
  max-width: 420px;
  text-align: center;
  font-size: 14px;
  color: var(--ink-2);
}
.viewer-plain b {
  color: var(--ink);
  overflow-wrap: anywhere;
}
.viewer-plain p {
  margin: 0;
}
.viewer-step {
  width: 44px;
  height: 64px;
  margin: 0 6px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 12px;
  background: var(--glass-strong);
  color: var(--ink);
  cursor: pointer;
}
.viewer-step.prev {
  grid-column: 1;
  grid-row: 1;
}
.viewer-step.next {
  grid-column: 3;
  grid-row: 1;
}
.viewer-step:disabled {
  opacity: 0.35;
  cursor: default;
}
.viewer-step[hidden] {
  display: none;
}
.viewer-meta {
  margin: 0;
  padding: 8px 16px;
  border-top: 1px solid var(--line);
  font-size: 12.5px;
  color: var(--ink-2);
}
.viewer-meta:empty {
  display: none;
}
@media (max-width: 640px) {
  .viewer {
    inset: 0;
    border-radius: 0;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .viewer-bar {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "name close" "actions actions";
  }
  .viewer-name {
    grid-area: name;
  }
  .viewer-actions {
    grid-area: actions;
    flex-wrap: wrap;
  }
  .viewer-bar > .icon-button {
    grid-area: close;
  }
  .viewer-step {
    position: absolute;
    top: 50%;
    z-index: 1;
    margin: -32px 0 0;
  }
  .viewer-step.prev {
    left: 6px;
  }
  .viewer-step.next {
    right: 6px;
  }
  .viewer-body {
    grid-template-columns: minmax(0, 1fr);
  }
  .viewer-stage {
    grid-column: 1;
  }
}

/* ---------- the Files page (plan 7.5) ---------- */

body[data-area="files"] .view {
  max-width: 1280px;
}
.files-top {
  margin: 0 0 14px;
}
.files-search {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 560px;
  height: 44px;
  padding: 0 14px;
  border-radius: 22px;
  color: var(--ink-3);
  background: var(--surface);
  box-shadow: var(--shadow-s), inset 0 0 0 1px var(--line);
}
.files-search:focus-within {
  box-shadow: var(--shadow-s), inset 0 0 0 2px var(--accent);
}
.files-search input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 15px;
}
.files-shell {
  display: grid;
  grid-template-columns: 264px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}
.files-folders {
  position: sticky;
  top: 12px;
  padding: 8px;
  border-radius: var(--r-l);
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.folder-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
}
.folder {
  width: 100%;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 4px 10px 4px 6px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.folder:hover {
  background: var(--accent-softer);
}
.folder[aria-current="true"] {
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 650;
}
.folder.sub {
  min-height: 36px;
  font-size: 13px;
  color: var(--ink-2);
}
.folder-indent {
  width: 32px;
}
.folder-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.folder-count {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.files-main {
  min-width: 0;
}
.files-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px 16px;
  margin: 0 0 12px;
}
.files-title {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  min-width: 0;
}
.files-title h2 {
  margin: 0 0 2px;
  font-size: clamp(20px, 2.4vw, 26px);
  font-weight: 650;
}
.files-title p {
  margin: 0;
  font-size: 13.5px;
}
.files-title a {
  color: var(--accent-text);
}
.folder-chips {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.folder-chip {
  padding: 0 12px;
}
.files-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin: 0 0 12px;
}
.files-tools[hidden] {
  display: none;
}
.files-select {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 4px 0 10px;
  border-radius: 18px;
  color: var(--ink-2);
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.files-select select {
  height: 100%;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
}
.files-tools .unit-pick {
  margin-left: auto;
}
@media (pointer: coarse) {
  .files-select {
    height: 44px;
  }
}

/* A file — the whole card opens it; "…" and "Restore" sit above the opening button. */
.file-tile,
.file-row {
  position: relative;
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-s), inset 0 0 0 1px var(--line);
}
.file-open {
  position: absolute;
  inset: 0;
  z-index: 0;
  border: 0;
  border-radius: inherit;
  background: transparent;
  cursor: pointer;
}
.file-open:hover {
  background: var(--accent-softer);
}
.file-tile > :not(.file-open),
.file-row > :not(.file-open) {
  position: relative;
  pointer-events: none;
}
.file-tile > button:not(.file-open),
.file-row > button:not(.file-open) {
  z-index: 1;
  pointer-events: auto;
}
.file-text {
  display: grid;
  gap: 2px;
  min-width: 0;
}
.file-pic {
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--glass-soft);
}
.file-pic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.file-pic.small {
  width: 44px;
  height: 44px;
  border-radius: 10px;
}
.file-pic.large {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: 10px;
}
/* A document has no picture: a lower card with its tile large, in its own colour. */
.file-pic.large.tile {
  aspect-ratio: 16 / 9;
}
.file-pic.large .doc-tile {
  transform: scale(1.6);
}
.files-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(172px, 1fr));
  gap: 12px;
}
.file-tile {
  display: grid;
  gap: 8px;
  padding: 8px;
  align-content: start;
}
.file-tile .file-more {
  position: absolute;
  top: 12px;
  right: 12px;
  background: var(--glass-strong);
}
.file-tile > .button {
  justify-self: start;
}
.files-rows {
  display: grid;
  gap: 8px;
}
.file-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 12px;
  min-height: 60px;
  padding: 8px 8px 8px 10px;
}
.file-message {
  white-space: nowrap;
  font-size: 13px;
}
.files-more {
  display: block;
  margin: 16px auto 0;
}
.files-more[hidden],
.files-empty[hidden] {
  display: none;
}
.files-empty {
  padding: 24px 0;
}
.files-back {
  margin: -4px 0 0 -8px;
}

/* Below 900 px: the folders are the first screen, a folder the next — with a way back (as the chat). */
@media (max-width: 899px) {
  .files-shell {
    grid-template-columns: minmax(0, 1fr);
  }
  .files-shell:not([data-open]) .files-main,
  .files-shell[data-open] .files-folders {
    display: none;
  }
  .files-folders {
    position: static;
  }
  .files-tools .unit-pick {
    margin-left: 0;
  }
  .file-row {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }
  .file-message {
    display: none;
  }
  .files-grid {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .up-bar i,
  .tl-node::before {
    transition: none;
  }
  /* The light still shows — it just doesn't fade. */
  .conversation .msg.lit .bubble,
  .conversation .msg.system.lit {
    animation: none;
    background: var(--accent-soft);
  }
  .sheet.tl-sheet {
    transition: none;
  }
}
@media (forced-colors: active) {
  .drop-zone {
    border-color: Highlight;
  }
  .up-bar i,
  .tl-node::before {
    background: Highlight;
  }
  .folder[aria-current="true"],
  .file-chip,
  .file-tile,
  .file-row,
  .viewer {
    border: 1px solid CanvasText;
  }
  .rail-strip-count:not(:empty) {
    border: 1px solid CanvasText;
  }
}

/* ---------- phase 2c: voice messages — the player in a bubble, "Download" where it can't play, the microphone's hints ---------- */

.voice-slot {
  min-width: 0;
}
.msg-files .voice {
  min-width: min(280px, 100%);
}
/* Fetching the sound on the first Play: the button dims a little, nothing spins. */
.voice.loading .voice-play {
  opacity: 0.6;
}
.voice.playing .voice-play {
  box-shadow: 0 0 0 4px var(--accent-soft);
}
/* A voice message this device can't play: what it is, and "Download". */
.voice.voice-off {
  grid-template-columns: auto minmax(0, 1fr) auto;
  padding: 8px 8px 8px 10px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  box-shadow: inset 0 0 0 1px var(--line);
}
.voice-off-words {
  display: grid;
  min-width: 0;
  font-size: 13.5px;
}
.voice-off-words small {
  color: var(--ink-3);
  font-size: 12.5px;
}
.mic-hint-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  width: 100%;
  justify-content: flex-end;
}
@media (forced-colors: active) {
  .voice.voice-off {
    border: 1px solid CanvasText;
  }
}

/* ---------- phase 2d: search and finish ---------- */

/* The day while the chat moves: one pill at the top of the list, gone a second after (notes 2a-31, 2b-32). */
.day-float {
  position: sticky;
  top: 0;
  z-index: 2;
  flex: 0 0 0;
  height: 0;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.day-float .day {
  margin: 8px 0 0;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity var(--fast, 160ms) var(--ease), transform var(--fast, 160ms) var(--ease);
}
.day-float.show .day {
  opacity: 1;
  transform: none;
}
.day-float .day:empty {
  display: none;
}
/* "Nothing found": the drawing, small enough to sit in the box with the field above it. */
/* One way to clear and close: the box's own "Close" — not also the browser's × in the field. */
.search-field input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}
.search-results .empty-state {
  padding: 16px 12px 20px;
}
.search-results .empty-art {
  width: 120px;
  height: 90px;
}
.search-results .skel-row {
  padding: 8px 10px;
}
.net-slot:empty {
  display: none;
}
@media (prefers-reduced-motion: reduce) {
  .day-float .day {
    transition: none;
    transform: none;
  }
}
@media (forced-colors: active) {
  .day,
  .net-banner {
    border: 1px solid CanvasText;
  }
  .search-hit mark {
    forced-color-adjust: none;
    color: HighlightText;
    background: Highlight;
  }
  .search-hit[aria-selected="true"] {
    outline: 2px solid Highlight;
    outline-offset: -2px;
  }
  .scrubber i {
    opacity: 1;
    background: CanvasText;
  }
  .tl-year-line,
  .scrubber i.year {
    forced-color-adjust: none;
    background: CanvasText;
  }
}

/* ---------- phase 3a: Contracts · Yarns & prices · Colours ---------- */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The three tabs: a pressed row like "Kg | Balls", that fits a 375 px phone without scrolling sideways. */
.tabs {
  display: flex;
  width: fit-content;
  max-width: 100%;
  margin: 0 0 20px;
  padding: 3px;
  border-radius: 999px;
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.tab-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  padding: 0 16px;
  border-radius: 999px;
  color: var(--ink-2);
  font-size: 14px;
  font-weight: 650;
  text-decoration: none;
  white-space: nowrap;
}
.tab-link:hover {
  color: var(--ink);
  text-decoration: none;
  background: var(--accent-softer);
}
.tab-link[aria-current="page"] {
  background: var(--surface);
  color: var(--accent-text);
  box-shadow: var(--shadow-s);
}
@media (max-width: 420px) {
  .tabs {
    width: 100%;
  }
  .tab-link {
    flex: 1 1 auto;
    padding: 0 10px;
    font-size: 13.5px;
  }
}

.page-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.section-head {
  margin: 28px 0 12px;
  font-size: 17px;
  font-weight: 650;
}
.card-lead {
  margin: -4px 0 12px;
  font-size: 14px;
}
.card-sub {
  margin: 18px 0 8px;
  font-size: 14px;
  font-weight: 650;
}
.card-meta {
  margin: 10px 0 0;
  font-size: 12.5px;
  color: var(--ink-3);
}
.card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.closure-help {
  margin: 0 0 8px;
  padding-left: 18px;
  font-size: 14px;
}
.flash {
  animation: flash 1.4s var(--ease);
}
@keyframes flash {
  0%,
  40% {
    box-shadow: var(--shadow-s), inset 0 0 0 2px var(--accent);
  }
}

/* The price list: one table, yarn × Dyed / Ecru / Hand-dyed. */
.table-wrap {
  max-width: 100%;
  overflow-x: auto;
}
.price-list {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.price-list th,
.price-list td {
  padding: 10px 12px 10px 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.price-list thead th {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.price-list tbody tr:last-child > * {
  border-bottom: 0;
}
.price-yarn span,
.price-list.entry th[scope="row"] span {
  display: block;
  font-weight: 650;
}
.price-yarn small,
.price-list.entry th[scope="row"] small {
  font-size: 12px;
  font-weight: 500;
}
.price-cell {
  min-width: 120px;
}
.price-cell .price {
  display: block;
  font-variant-numeric: tabular-nums;
}
.price-cell small,
.price-cell .entered {
  display: block;
  font-size: 12px;
  color: var(--ink-3);
}
.price-cell .link-button.entered {
  min-height: 0;
  padding: 0;
  text-align: left;
  color: var(--accent-text);
}
.price-cell .upcoming {
  color: var(--ink-2);
  font-weight: 600;
}
.price-list .act {
  text-align: right;
  white-space: nowrap;
}
.earlier-wrap {
  margin-top: 8px;
}
.earlier-fold svg {
  transform: rotate(-90deg);
}
.earlier-fold[aria-expanded="true"] svg {
  transform: none;
}
.earlier {
  padding: 4px 0 0 26px;
}
.earlier-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 4px;
  font-size: 13.5px;
}

/* Below 720 px a row of the table becomes a small card: the yarn, then each price with its variant's name. */
@media (max-width: 719px) {
  .price-list thead {
    display: none;
  }
  .price-list,
  .price-list tbody,
  .price-list tr {
    display: block;
  }
  .price-list tr {
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
  }
  .price-list tbody tr:last-child {
    border-bottom: 0;
  }
  .price-list th,
  .price-list td {
    display: grid;
    grid-template-columns: 112px minmax(0, 1fr);
    gap: 2px 10px;
    padding: 4px 0;
    border: 0;
  }
  .price-list th[scope="row"] {
    display: flex;
    align-items: baseline;
    gap: 8px;
  }
  .price-list td[data-label]::before {
    content: attr(data-label);
    grid-row: span 6;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-3);
  }
  .price-list td.act {
    display: block;
    text-align: left;
    padding-top: 6px;
  }
  .price-cell {
    min-width: 0;
  }
}

/* One card per yarn, with the yarn's own colour as a thin bar on the left. */
.yarn-cards {
  display: grid;
  gap: 16px;
}
.yarn-card {
  position: relative;
  overflow: hidden;
  scroll-margin-top: 80px;
}
.yarn-card::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 5px;
  background: var(--yarn, var(--accent));
}
.yarn-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px 12px;
}
.card .yarn-head h3 {
  flex: 1;
  min-width: 0;
  margin: 0;
}
/* The whole line opens and folds the card. */
.yarn-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.yarn-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}
.yarn-title {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.yarn-chev {
  display: inline-flex;
  margin-left: auto;
  color: var(--ink-3);
  transition: transform 0.15s ease;
}
.yarn-toggle[aria-expanded="true"] .yarn-chev {
  transform: rotate(180deg);
}
@media (prefers-reduced-motion: reduce) {
  .yarn-chev {
    transition: none;
  }
}
.yarn-code {
  font-size: 13px;
  color: var(--ink-3);
  overflow-wrap: anywhere;
}
.yarn-status {
  margin: 12px 0 4px;
}
.yarn-status.ok {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--ink-2);
}
.yarn-status.ok svg {
  flex: none;
  color: var(--good);
}
.yarn-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 4px 28px;
}
.yarn-block {
  min-width: 0;
  padding-top: 12px;
}
.yarn-block h4,
.inline-form h4 {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 650;
  color: var(--ink-2);
}
.yarn-block.locked h4 svg {
  color: var(--ink-3);
}
.facts {
  display: grid;
  grid-template-columns: minmax(110px, auto) minmax(0, 1fr);
  gap: 6px 14px;
  margin: 0;
  font-size: 14px;
}
.facts dt {
  color: var(--ink-3);
  font-size: 13px;
}
.facts dd {
  margin: 0;
  overflow-wrap: anywhere;
}
.locked .facts dd {
  color: var(--ink-2);
}
.yarn-docs {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 4px;
  font-size: 13.5px;
}
.yarn-docs .link-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-align: left;
  overflow-wrap: anywhere;
}

/* Forms in place on a card, and in a sheet. */
.inline-form,
.sheet-form {
  display: grid;
  gap: 12px;
}
.inline-form {
  padding: 14px;
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
}
.inline-form > h3 {
  margin: 0;
}
.inline-form p,
.sheet-form p {
  margin: 0;
}
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: 10px 14px;
}
.form-grid > .field {
  align-content: start;
}
.form-grid.three {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr));
}
.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.form-error {
  margin: 0;
  padding: 8px 12px;
  border-radius: var(--r-s);
  font-size: 14px;
  font-weight: 600;
  color: color-mix(in srgb, var(--bad) 75%, var(--ink));
  background: color-mix(in srgb, var(--bad) 10%, transparent);
}
.form-error[hidden] {
  display: none;
}
.putup-line {
  font-size: 14px;
}
.putup-preview {
  font-weight: 600;
}
.behalf {
  display: grid;
  gap: 10px;
}
.behalf-note {
  --c: var(--accent);
  margin: 0;
  font-weight: 500;
}
.file-field .slot-step-what {
  margin-top: 2px;
}
.sheet-form .field input[type="date"],
.inline-form .field input[type="date"] {
  min-width: 0;
}
.price-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 8px 12px;
  margin: 0;
  padding: 12px;
  border: 0;
  border-radius: var(--r-m);
  box-shadow: inset 0 0 0 1px var(--line);
}
.price-row legend {
  float: left;
  grid-column: 1 / -1;
  width: 100%;
  padding: 0;
  font-weight: 650;
  font-size: 15px;
}
.price-row .price-note-field {
  grid-column: 1 / -1;
}
.price-list.entry input {
  width: 100%;
  min-width: 80px;
  min-height: 40px;
  padding: 6px 10px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
}
.price-list.entry td small {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
}
.form-steps {
  display: grid;
  gap: 14px;
  margin: 0;
  padding-left: 22px;
}
.form-steps > li::marker {
  font-weight: 650;
  color: var(--ink-3);
}
.more-details {
  display: grid;
  gap: 10px;
  padding: 4px 0;
}
.more-details > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  font-weight: 650;
  cursor: pointer;
  list-style: none;
}
.more-details > summary::-webkit-details-marker {
  display: none;
}
.more-details > summary svg {
  transform: rotate(-90deg);
  transition: transform var(--fast) var(--ease);
}
.more-details[open] > summary svg {
  transform: none;
}
.more-details[open] > :not(summary) {
  margin-top: 8px;
}
.more-details h4 {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--ink-2);
}

/* The properties editor: name · value · unit · remove. */
.spec-head,
.spec-row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.4fr) minmax(0, 0.8fr) 40px;
  gap: 6px 8px;
  align-items: center;
}
.spec-head {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.spec-rows {
  display: grid;
  gap: 6px;
}
.spec-row input,
.closure-row input,
.closure-row select {
  width: 100%;
  min-width: 0;
  min-height: 40px;
  padding: 6px 10px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
}
.spec-row.fixed input[readonly] {
  border-color: transparent;
  background: transparent;
  color: var(--ink-2);
  padding-left: 0;
}

/* Closures: kind, from–to, the words Samil wrote. */
.closures-card {
  margin-top: 24px;
  scroll-margin-top: 80px;
}
.closure-list,
.lead-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 8px;
  font-size: 14px;
}
.closure-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
}
.closure-when {
  font-variant-numeric: tabular-nums;
}
.closure-label {
  color: var(--ink-2);
}
.lead-list li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2px 12px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
}
.lead-list li:last-child {
  border-bottom: 0;
}
.lead-yarn {
  font-weight: 600;
}
.closure-rows {
  display: grid;
  gap: 10px;
}
.closure-row {
  display: grid;
  grid-template-columns: minmax(130px, 1fr) minmax(130px, 1fr) minmax(130px, 1fr) minmax(0, 2fr) 40px;
  align-items: end;
  gap: 8px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
@media (max-width: 719px) {
  .closure-row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 44px;
  }
  .closure-row > label:first-child {
    grid-column: 1 / 3;
  }
  .closure-row > .icon-button {
    grid-column: 3;
    grid-row: 1;
  }
  .closure-row .closure-what {
    grid-column: 1 / -1;
  }
}
.home-closures {
  margin-top: 28px;
}
.home-closures .closures-card {
  margin-top: 0;
  max-width: 680px;
}

/* Colours: per yarn VBM's list, and Samil's own two fields. */
.yarn-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 16px;
}
.colour-group {
  margin-bottom: 16px;
  scroll-margin-top: 80px;
}
.yarn-dot {
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--yarn, var(--accent));
}
.colour-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.colour-table th,
.colour-table td {
  padding: 8px 10px 8px 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: middle;
}
.colour-table thead th {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  white-space: nowrap;
}
.colour-table tr.off > td:not(.samil-cell):not(.samil-save) {
  color: var(--ink-3);
}
.colour-table .ean {
  font-variant-numeric: tabular-nums;
  font-size: 13px;
}
.colour-pic-cell .swatch {
  display: block;
}
.colour-pic {
  display: block;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  object-fit: cover;
}
.colour-marks-cell .tag {
  margin: 0 4px 0 0;
}
.samil-cell input {
  width: 100%;
  min-width: 110px;
  min-height: 36px;
  padding: 4px 10px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}
.samil-cell .form-error {
  margin-top: 4px;
  padding: 4px 8px;
  font-size: 12.5px;
}
.samil-save {
  white-space: nowrap;
}
.colour-form {
  display: contents;
}
@media (max-width: 719px) {
  .colour-table thead {
    display: none;
  }
  .colour-table,
  .colour-table tbody {
    display: block;
  }
  .colour-table tr {
    display: grid;
    grid-template-columns: auto 32px minmax(0, 1fr);
    gap: 4px 10px;
    align-items: center;
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
  }
  .colour-table td {
    padding: 0;
    border: 0;
  }
  .colour-table td.colour-no {
    grid-column: 1;
    grid-row: 1;
  }
  .colour-table td.colour-pic-cell {
    grid-column: 2;
    grid-row: 1;
  }
  .colour-table td[data-label="Danish name"] {
    grid-column: 3;
    grid-row: 1;
    font-weight: 600;
  }
  .colour-table td[data-label]:not([data-label="Danish name"]):not(.colour-no),
  .colour-table td.colour-marks-cell,
  .colour-table td.samil-save {
    grid-column: 1 / -1;
  }
  .colour-table td[data-label]:not([data-label="Danish name"]):not(.colour-no) {
    display: grid;
    grid-template-columns: 96px minmax(0, 1fr);
    gap: 8px;
    align-items: center;
  }
  .colour-table td[data-label]:not([data-label="Danish name"]):not(.colour-no)::before {
    content: attr(data-label);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-3);
  }
  .colour-table td.colour-marks-cell:empty {
    display: none;
  }
  .colour-table td.samil-save {
    display: flex;
    justify-content: flex-end;
  }
  .samil-cell input {
    min-width: 0;
  }
}

/* The Send question's "Expected ready ≈ …" lines (VBM only). */
.dialog-list {
  margin: -8px 0 18px;
  padding-left: 18px;
  display: grid;
  gap: 4px;
  font-size: 14px;
  color: var(--ink-2);
}
/* Files: "Contracts & yarn" one step further in, under "From Samil". */
.folder-indent.deep {
  width: 48px;
}

/* A form sheet stands in the middle of a wide screen instead of across it. */
@media (min-width: 900px) {
  .sheet.form-sheet {
    left: 50%;
    right: auto;
    bottom: auto;
    top: 6vh;
    width: min(640px, 92vw);
    height: auto;
    max-height: 88vh;
    border-radius: 24px;
    transform: translate(-50%, 24px);
    opacity: 0;
    transition: transform var(--mid) var(--spring), opacity var(--mid) var(--ease);
  }
  .sheet.form-sheet.wide {
    width: min(860px, 94vw);
  }
  .sheet.form-sheet.show {
    transform: translate(-50%, var(--drag, 0px));
    opacity: 1;
  }
  .sheet.form-sheet .sheet-handle {
    visibility: hidden;
    height: 16px;
  }
}

@media (pointer: coarse) {
  .tab-link,
  .more-details > summary,
  .spec-row input,
  .closure-row input,
  .closure-row select,
  .price-list.entry input,
  .samil-cell input {
    min-height: 44px;
  }
  .spec-row .icon-button,
  .closure-row .icon-button {
    width: 44px;
    height: 44px;
  }
  .price-cell .link-button.entered {
    min-height: 32px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .flash {
    animation: none;
  }
  .sheet.form-sheet {
    transition: none;
  }
}
@media (forced-colors: active) {
  .tab-link[aria-current="page"] {
    outline: 2px solid CanvasText;
  }
  .yarn-card::before,
  .yarn-dot {
    forced-color-adjust: none;
    background: CanvasText;
  }
  .form-error,
  .inline-form {
    border: 1px solid CanvasText;
  }
}

/* ---------- phase 3b: Contracts — the cards, the forms, the order page's contract, Home ---------- */

/* Four tabs on a phone: the short word, so the row fits 375 px without scrolling sideways. */
.tab-short {
  display: none;
}
@media (max-width: 560px) {
  .tab-long {
    display: none;
  }
  .tab-short {
    display: inline;
  }
}

/* Open · Closed — a pressed row like the tabs. */
.seg {
  display: flex;
  width: fit-content;
  margin: 0 0 16px;
  padding: 3px;
  border-radius: 999px;
  background: var(--glass-soft);
  box-shadow: inset 0 0 0 1px var(--line);
}
.seg-button {
  min-height: 34px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: 14px;
  font-weight: 650;
  cursor: pointer;
}
.seg-button:hover {
  color: var(--ink);
  background: var(--accent-softer);
}
.seg-button[aria-pressed="true"] {
  background: var(--surface);
  color: var(--accent-text);
  box-shadow: var(--shadow-s);
}
.seg-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.contract-cards {
  display: grid;
  gap: 16px;
}
.contract-card {
  position: relative;
  overflow: hidden;
  scroll-margin-top: 80px;
}
.contract-card::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 5px;
  background: var(--st-ready);
}
.contract-card.is-requested::before {
  background: var(--st-sent);
}
.contract-card.is-offered::before {
  background: var(--st-change);
}
.contract-card.is-closed::before {
  background: var(--line);
}
.contract-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 6px 12px;
  margin-bottom: 8px;
}
.contract-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 10px;
  min-width: 0;
}
.card .contract-name h3 {
  margin: 0;
  font-size: 17px;
  overflow-wrap: anywhere;
}
.contract-name h3:focus {
  outline: none;
}
.contract-signed {
  font-size: 13px;
  color: var(--ink-3);
}
.contract-entered {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  font-size: 13.5px;
  color: var(--accent-text);
}
.contract-entered svg {
  flex: none;
}
.contract-wait,
.contract-none {
  margin: 0 0 8px;
  font-size: 14px;
}
.contract-card .notice {
  margin: 4px 0 10px;
}

/* One line per contract code: yarn · kg · used · remaining · €/kg. */
.contract-lines {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.contract-lines th,
.contract-lines td {
  padding: 8px 12px 8px 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.contract-lines thead th {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.contract-lines .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.contract-lines tbody tr:last-child > * {
  border-bottom: 0;
}
.contract-yarn {
  font-weight: 400;
}
.contract-yarn > * {
  display: block;
}
.contract-code {
  font-weight: 650;
}
.contract-yarn small {
  font-size: 12.5px;
}
@media (max-width: 719px) {
  .contract-lines thead {
    display: none;
  }
  .contract-lines,
  .contract-lines tbody {
    display: block;
  }
  .contract-lines tr {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
  }
  .contract-lines tbody tr:last-child {
    border-bottom: 0;
  }
  .contract-lines th,
  .contract-lines td {
    padding: 0;
    border: 0;
  }
  .contract-lines th[scope="row"] {
    grid-column: 1 / -1;
  }
  /* On a phone a request shows only what it has: kg and the price to come. */
  .contract-lines td.empty[data-label] {
    display: none;
  }
  .contract-lines td[data-label] {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    text-align: right;
  }
  .contract-lines td[data-label]::before {
    content: attr(data-label);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-3);
  }
}

/* The thread: request → reply → accepted, one line of small steps. */
.contract-thread {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 0;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
  color: var(--ink-2);
}
.contract-thread li + li::before {
  content: "→";
  margin: 0 8px;
  color: var(--ink-3);
}
.contract-pdf {
  margin: 10px 0 0;
  font-size: 14px;
}
.contract-pdf .link-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-align: left;
  overflow-wrap: anywhere;
}
.contract-actions[hidden],
.contract-form-slot:empty {
  display: none;
}
.contract-form-slot {
  margin-top: 12px;
}

/* Reply / Update: the PDF, the number, "Valid until", then kg and €/kg per line. */
.until-field {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.until-field legend {
  padding: 0;
  margin-bottom: 4px;
}
.until-kind {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  font-weight: 500;
}
.until-month {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 8px;
}
.until-month[hidden],
.until-field input[hidden] {
  display: none;
}
.contract-form > p.muted,
.request-form > p.muted {
  font-size: 14px;
}
.contract-form-lines {
  display: grid;
  gap: 10px;
}
.contract-form-line {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr);
  align-items: end;
  gap: 4px 12px;
  padding: 10px 12px;
  border-radius: var(--r-m);
  box-shadow: inset 0 0 0 1px var(--line);
}
.contract-form-yarn {
  align-self: center;
  font-size: 14px;
}
.contract-form-list {
  grid-column: 2 / -1;
}
/* Ecru price (30/10): its own row under the €/kg, with its hint; on the card, under the €/kg. */
.contract-form-ecru {
  grid-column: 2 / -1;
}
.contract-ecru {
  display: block;
  color: var(--ink-3);
  font-size: 13px;
  white-space: nowrap;
}
@media (max-width: 560px) {
  .contract-form-line {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  .contract-form-yarn,
  .contract-form-list,
  .contract-form-ecru {
    grid-column: 1 / -1;
  }
}

/* Samil's "Ask VBM for a new contract", under an agreed line. */
.contract-ask-wrap {
  display: grid;
  gap: 4px;
  margin-top: 6px;
}
.contract-ask {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 0;
  font-size: 13.5px;
  text-align: left;
}
.contract-asked {
  margin-top: 6px;
  font-size: 12.5px;
  color: var(--ink-2);
}
.contract-asked svg {
  color: var(--good);
  vertical-align: -2px;
}

/* VBM's own facts on a card (served styles; the words come from VBM's module only). */
.contract-vbm {
  display: grid;
  gap: 4px;
  margin: 0 0 10px;
}
.contract-vbm p {
  margin: 0;
}
.contract-until {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  font-size: 14px;
}
.ct-days {
  --c: var(--st-idle);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 24px;
  padding: 0 10px 0 8px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 650;
  color: color-mix(in srgb, var(--c) 75%, var(--ink));
  background: color-mix(in srgb, var(--c) var(--tone), transparent);
}
.ct-days.ct-soon {
  --c: var(--warn);
}
.ct-days.ct-out {
  --c: var(--bad);
}
.contract-note {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: 13.5px;
  color: var(--ink-2);
}
.contract-note svg {
  flex: none;
  margin-top: 2px;
}
.contract-line-vbm {
  display: grid;
  gap: 2px;
  margin-top: 4px;
  font-size: 12.5px;
  color: var(--ink-2);
}
.ct-over {
  font-weight: 650;
  color: color-mix(in srgb, var(--bad) 75%, var(--ink));
}
.ct-soon-text {
  font-weight: 600;
  color: color-mix(in srgb, var(--warn) 75%, var(--ink));
}
.ct-nudge .link-button {
  min-height: 0;
  padding: 0;
  font-size: 12.5px;
}
.close-reasons {
  margin: 0;
  padding: 0;
  border: 0;
}

/* Request a contract: one row per yarn — yarn, kg, remove; the latest price under it. */
.request-rows {
  display: grid;
  gap: 12px;
}
.request-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) 40px;
  align-items: end;
  gap: 4px 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.request-row .icon-button[hidden] {
  visibility: hidden;
  display: inline-flex;
}
.request-price {
  grid-column: 1 / -1;
}
.request-share {
  color: var(--ink-2);
}
.import-list .muted th,
.import-list tr.muted td {
  color: var(--ink-3);
}

/* Samil's Home: "Your contracts" — kg, used, left. No dates. */
.home-contracts {
  margin-top: 28px;
}
.home-contracts-card {
  max-width: 680px;
}
.home-contracts-card h3 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
}
.home-contract-list,
.home-contract-lines {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 10px;
}
.home-contract-lines {
  gap: 4px;
  margin-top: 4px;
  font-size: 14px;
}
.home-contract-lines li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2px 12px;
}
.home-contract-no {
  font-weight: 650;
}
.home-contract-figures {
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* The order page: "Lines draw on contract …" in the confirm form, the Contract field, VBM's provisional draws. */
.confirm-drawn {
  margin: 0;
  font-size: 14px;
}
.confirm-drawn > p {
  margin: 0 0 4px;
  font-weight: 600;
}
/* Phase 3d: one short line per ordered line — the colour left, what it draws on right. */
.confirm-draws {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
  font-size: 13.5px;
}
.confirm-draws li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2px 12px;
  padding: 3px 0;
  border-bottom: 1px dashed var(--line);
}
.confirm-draw-to {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.confirm-draws .on-list .confirm-draw-to {
  font-weight: 500;
  color: var(--ink-2);
}
/* The contract chip on a confirmed line in Lines (both sides). */
.tag-contract {
  font-variant-numeric: tabular-nums;
}
.lots-cell {
  white-space: nowrap;
}
.confirm-contract select {
  min-width: 11em;
}
.confirm-contract-cell {
  white-space: nowrap;
}
.draw-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  margin: 0 0 12px;
  font-size: 13.5px;
  color: var(--ink-2);
}
.draw-note > svg {
  flex: none;
}
.assign-lines {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 2px;
  font-size: 14px;
}
.assign-form {
  margin-top: 8px;
}

@media (pointer: coarse) {
  .seg-button,
  .contract-ask,
  .contract-pdf .link-button {
    min-height: 44px;
  }
  .request-row .icon-button {
    width: 44px;
    height: 44px;
  }
  .request-row {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) 44px;
  }
}
@media (forced-colors: active) {
  .seg-button[aria-pressed="true"] {
    outline: 2px solid CanvasText;
  }
  .contract-card::before {
    forced-color-adjust: none;
    background: CanvasText;
  }
  .ct-days {
    border: 1px solid CanvasText;
  }
}
