/* Reusable components: buttons, badges, status lights, table, filters, cards, states. */

/* ---- Buttons ---- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 42px;
  padding: 0 var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: 600;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}

.btn:not(:disabled):hover {
  background: var(--surface-sunken);
  border-color: var(--border-strong);
}

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.btn.primary:not(:disabled):hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.btn.ghost {
  border-color: transparent;
  background: transparent;
}

.btn.ghost:not(:disabled):hover {
  background: var(--surface-sunken);
}

.btn.danger {
  border-color: var(--status-pending);
  color: var(--status-pending);
}

.btn.danger:not(:disabled):hover {
  background: var(--status-pending);
  border-color: var(--status-pending);
  color: #fff;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--surface-sunken);
  border-color: var(--border);
  color: var(--ink-muted);
}

.btn.small {
  height: 30px;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
}

.btn.icon-only {
  width: 42px;
  padding: 0;
}

.btn.icon-only .icon {
  width: 18px;
  height: 18px;
}

/* ---- Status light (the signature) ---- */
/* A glowing navigation-light dot + label, driven by data-status. */

.status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-soft);
  white-space: nowrap;
}

.status .light {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.status[data-status="pending"] .light {
  background: var(--status-pending);
  box-shadow: 0 0 0 3px var(--status-pending-soft);
}

.status[data-status="progress"] .light {
  background: var(--status-progress);
  box-shadow: 0 0 0 3px var(--status-progress-soft);
}

.status[data-status="done"] .light {
  background: var(--status-done);
  box-shadow: 0 0 0 3px var(--status-done-soft);
}

.status[data-status="na"] .light {
  background: var(--status-na);
  box-shadow: 0 0 0 3px var(--status-na-soft);
}

/* FB-01: semaphore coloured by aggregate deadline urgency, not lifecycle. */
.status[data-urgency="overdue"] .light {
  background: var(--status-pending);
  box-shadow: 0 0 0 3px var(--status-pending-soft);
}

.status[data-urgency="soon"] .light {
  background: var(--status-progress);
  box-shadow: 0 0 0 3px var(--status-progress-soft);
}

.status[data-urgency="active"] .light {
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.status[data-urgency="done"] .light {
  background: var(--status-done);
  box-shadow: 0 0 0 3px var(--status-done-soft);
}

/* FB22-01: a cancelled file is terminal like a closed one but nothing about it
   was accomplished, so it takes the grey light and never the green. */
.status[data-urgency="cancelled"] .light {
  background: var(--status-na);
  box-shadow: 0 0 0 3px var(--status-na-soft);
}

/* ---- Badges & chips ---- */

.badge-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  color: var(--ink-soft);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.badge-pill.risk {
  background: var(--risk-soft);
  color: var(--risk);
}

/* FB-04: inactivity escalation indicator */
.badge-pill.stale {
  background: var(--status-pending-soft);
  color: var(--status-pending);
}

/* OPS-18: active-risk icons — one per risk, differentiated by shape, in the risk tone. */
.risk-icons {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  vertical-align: middle;
}

.risk-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-sm);
  background: var(--risk-soft);
  color: var(--risk);
}

/* Deadline countdown pill */
.deadline {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.deadline.overdue {
  background: var(--status-pending-soft);
  color: var(--status-pending);
}

.deadline.soon {
  background: var(--status-progress-soft);
  color: var(--status-progress);
}

.deadline.ok {
  background: var(--status-na-soft);
  color: var(--ink-soft);
}

/* Time-window deadline whose reference event hasn't happened yet — provisional,
   not a real due date (no overdue/soon alert). */
.deadline.window {
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px dashed var(--accent);
}

/* FB7-05: file opened without a clean recap — deadlines not loaded yet. */
.deadline.pending {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Nobody assigned to a file slot reads the whole app: every write action is
   hidden. Set on <body> by the shell, and on the file screens per file — works
   on dynamically rendered controls too, since it's a descendant rule. */
.read-only [data-write-action] { display: none !important; }

/* Critical-deadline flag: wider alert window and supervisor escalation. */
.crit-flag {
  display: inline-flex;
  align-items: center;
  padding: 1px 6px;
  border: 1px solid var(--urgency-crit);
  border-radius: var(--radius-pill);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--urgency-crit);
  line-height: 1.5;
}

/* Contract-type chip in the operations list — color-coded by type. */
.type-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.type-chip::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.type-chip[data-type="Voyage"] { background: var(--accent-soft); color: var(--accent); }
.type-chip[data-type="Time"] { background: var(--status-progress-soft); color: var(--status-progress); }
.type-chip[data-type="COA"] { background: var(--risk-soft); color: var(--risk); }

.stage-cell {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

/* FB-05: quick "mark current task done" button in the Stage cell.
   FB6-02: quick "load ETA notice" button shares the same shape. */
.stage-done-btn,
.stage-eta-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: var(--space-2);
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-faint);
  cursor: pointer;
  vertical-align: middle;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.stage-done-btn:hover {
  color: var(--status-done);
  border-color: var(--status-done);
}

.stage-eta-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.stage-cell.stage-done {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--status-done);
  font-weight: 600;
}

/* OPS-20: reassign action in the Operator cell — surfaces on row hover. */
.op-operator {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.op-reassign {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.row-link:hover .op-reassign,
.op-reassign:focus-visible {
  opacity: 1;
}

.op-reassign:hover {
  color: var(--accent);
  border-color: var(--border);
  background: var(--surface-sunken);
}

/* ---- Filter toolbar ---- */

.toolbar {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: end;
  gap: var(--space-3) var(--space-2);
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: var(--space-4);
}

@media (max-width: 1100px) {
  .toolbar { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .toolbar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.quick-filters {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.quick-filters-label {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-faint);
  margin-right: var(--space-1);
}

.quick-filters-note {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.chip-toggle {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.chip-toggle:hover {
  border-color: var(--accent);
}

.chip-toggle.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.field label {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-faint);
}

.input,
.select {
  height: 38px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background-color: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--text-base);
  appearance: none;
}

.input {
  padding: 0 var(--space-3);
}

.input:disabled,
.select:disabled {
  background-color: var(--surface-sunken);
  color: var(--ink-faint);
  cursor: not-allowed;
}

/* Locked, not unavailable: the field is settled by a rule and its value is the
   point of it, so the text stays legible while the control stops taking input. */
.field.locked .input:disabled,
.field.locked .select:disabled {
  color: var(--ink);
  cursor: default;
}

/* A select that can't be opened doesn't offer to open: the chevron goes and the
   value takes back the room it was holding. */
.select:disabled {
  background-image: none;
  padding-right: var(--space-3);
}

.select {
  padding: 0 var(--space-6) 0 var(--space-3);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%23425667' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  cursor: pointer;
  /* The height is fixed, so an option longer than the control has to be clipped
     rather than wrapped: with appearance:none the selected text is laid out like
     any other content and a second line spills out of the box. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- Multiselect over a closed list (js/multiselect.js) ---- */

/* Reads as a form control at rest and grows only with what is picked, so a field
   whose answer is normally one or two values doesn't cost the height of the whole
   option list. */
.multiselect {
  position: relative;
}

.ms-control {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 38px;
  padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--text-base);
  text-align: left;
  cursor: pointer;
}

.multiselect.is-open .ms-control,
.ms-control:focus-visible {
  border-color: var(--accent);
  outline: none;
}

.ms-values {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  flex: 1;
  min-width: 0;
}

.ms-placeholder {
  color: var(--ink-faint);
}

.ms-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-1) 2px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
}

.ms-chip-remove {
  display: inline-flex;
  align-items: center;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  opacity: 0.65;
  cursor: pointer;
}

.ms-chip-remove:hover {
  opacity: 1;
}

.ms-caret {
  display: inline-flex;
  color: var(--ink-faint);
}

/* Floats over the form, and fixed rather than absolute: these sit inside a
   scrolling dialog, and an absolutely positioned list is clipped by it. Fixed
   takes the viewport as its containing block, so neither the modal body's scroll
   nor the dialog's overflow reaches it — the placement comes from
   js/multiselect.js, which also flips it above when there is no room below. */
/* Tall enough that a closed list of five options with their descriptions fits
   without scrolling — the cap is the fallback for a longer list, and the JS
   narrows it further when the viewport has less room than this. */
.ms-list {
  position: fixed;
  z-index: 30;
  max-height: 24rem;
  overflow-y: auto;
  padding: var(--space-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}

.ms-option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2);
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

.ms-option:hover {
  background: var(--surface-sunken);
}

.ms-check {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-top: 2px;
  border: 1px solid var(--border-strong);
  border-radius: 3px;
  background: var(--surface);
}

.ms-option[aria-selected="true"] .ms-check {
  border-color: var(--accent);
  background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' d='m5 12 5 5L19 7'/%3E%3C/svg%3E") center / 12px no-repeat;
}

.ms-option-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.ms-option-name {
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 600;
}

.ms-option-desc {
  color: var(--ink-faint);
  font-size: var(--text-xs);
}

/* Stylable native dropdown (Edge/Chrome); falls back to the OS popup elsewhere */
@supports (appearance: base-select) {
  .select {
    appearance: base-select;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    background-image: none;
    /* inline-flex shrinks to content: without a min width the chevron's
       margin-left:auto has no room and sticks to the label. */
    min-width: 9rem;
    /* the large padding-right was for the fallback's background chevron; here the
       chevron is a flex item, so it can sit closer to the edge. */
    padding-right: var(--space-3);
  }

  .select::picker-icon {
    content: "";
    width: 11px;
    height: 7px;
    margin-left: auto;
    background-color: var(--ink-soft);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E") no-repeat center / contain;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E") no-repeat center / contain;
    transition: transform var(--dur-fast) var(--ease);
  }

  .select:open::picker-icon {
    transform: rotate(180deg);
  }

  /* Same as the fallback's chevron: a locked select doesn't offer to open. */
  .select:disabled::picker-icon {
    display: none;
  }

  ::picker(select) {
    appearance: base-select;
    padding: var(--space-1);
    margin-top: var(--space-1);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg);
  }

  .select option {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    font-size: var(--text-base);
    color: var(--ink);
  }

  .select option::checkmark {
    display: none;
  }

  .select option:hover {
    background: var(--accent-soft);
    color: var(--accent);
  }

  .select option:checked {
    background: var(--accent);
    color: var(--accent-ink);
  }
}

.input::placeholder {
  color: var(--ink-muted);
}

.input[type="search"]::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  cursor: pointer;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23d63429' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6 6 18'/%3E%3C/svg%3E") no-repeat center / contain;
}

.input:focus,
.select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--focus-ring);
  background: var(--surface);
}

.toolbar .field {
  flex: 1;
  min-width: 0;
}

/* Grid items can't shrink below their content unless the controls can too. */
.toolbar .field .input,
.toolbar .field .select {
  width: 100%;
  min-width: 0;
}

/* A control that shouldn't stretch to fill the row when it wraps to its own
   line (e.g. the Group selector). Sized like a standard filter select. */
.toolbar .field.field-inline {
  flex: 0 1 200px;
}

/* ---- Table ---- */

.table-wrap {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* no overflow clip: it would trap the sticky thead. Corners rounded on the edge cells instead. */
}

/* Inside a panel the panel already frames the table — drop the wrap's own box. */
.panel-body .table-wrap {
  background: transparent;
  border: none;
  border-radius: 0;
}

/* Detail tab tables live in the narrow main column of the 2-col detail grid, so
   a min-width table (e.g. the 9-column hire schedule) would otherwise push the
   whole content wider than the viewport. Scroll it inside its own box instead.
   These tabs are short lists, so this doesn't affect the sticky thead used on
   the full-width operations / invoicing lists. The same applies to any table
   nested in a panel body (e.g. the COA shipments list): it sits in a narrow
   column, so it scrolls in its own box rather than dragging the whole page.
   Full-width list pages keep the table directly under .inner (not a panel). */
.tab-panel .table-scroll,
.panel-body .table-scroll {
  overflow-x: auto;
}

/* Between the card breakpoint and a wide desktop the content column is narrower
   than the table itself, so a full-width list would spill out of its panel and
   drag the page sideways (visible with the sidebar open around 1100px). Scroll
   it inside its own box in that range; the sticky thead is given up there
   because the scroller becomes its containing block. */
@media (min-width: 992px) and (max-width: 1359px) {
  .table-scroll {
    overflow-x: auto;
  }
}

table.data {
  width: 100%;
  min-width: 940px; /* below this the table scrolls horizontally instead of clipping */
  border-collapse: collapse;
  font-size: var(--text-sm);
}

table.data.files-list {
  min-width: 0;
}

table.data.files-list tbody tr:last-child td:first-child {
  border-bottom-left-radius: var(--radius);
}

table.data.files-list tbody tr:last-child td:last-child {
  border-bottom-right-radius: var(--radius);
}

table.data th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: var(--surface-sunken);
  box-shadow: inset 0 -1px 0 var(--border); /* collapsed borders detach on scroll; shadow rides along */
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 1;
}

table.data th[data-sort] {
  cursor: pointer;
  user-select: none;
}

table.data th[data-sort]:hover {
  color: var(--ink-soft);
}

table.data th[data-sort]::after {
  content: "↕";
  margin-left: var(--space-2);
  font-size: 0.9em;
  opacity: 0.3;
}

table.data th[aria-sort="ascending"]::after {
  content: "↑";
  opacity: 1;
}

table.data th[aria-sort="descending"]::after {
  content: "↓";
  opacity: 1;
}

table.data thead th:first-child {
  border-top-left-radius: var(--radius);
}

table.data thead th:last-child {
  border-top-right-radius: var(--radius);
}

/* Once pinned, the rounded corners would leave a notch against the card edge — flatten them. */
.content.scrolled table.data thead th {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

table.data td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  color: var(--ink-soft);
  vertical-align: middle;
}

table.data tbody tr:last-child td {
  border-bottom: none;
}

table.data tbody tr:hover {
  background: var(--row-hover);
}

/* Group header row (e.g. Files grouped by document type). */
table.data tbody tr.group-row td {
  padding: var(--space-2) var(--space-4);
  background: var(--surface-sunken);
  color: var(--ink);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

table.data tbody tr.group-row:hover td {
  background: var(--surface-sunken);
}

.group-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--space-1);
  margin-left: var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--border);
  color: var(--ink-soft);
  font-size: var(--text-xs);
  font-weight: 700;
}

/* Stacked (card) mode: a group header reads as a plain section band, not a card,
   and drops the empty data-label slot so its title stays left-aligned. */
@media (max-width: 991px) {
  table.data tbody tr.group-row {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
    margin: var(--space-4) 0 var(--space-2);
  }
  table.data tbody tr.group-row td {
    justify-content: flex-start;
    padding: var(--space-2) var(--space-1);
    border-bottom: 1px solid var(--border);
  }
  table.data tbody tr.group-row td::before { content: none; }
}

/* Version toggle + history (Files tab) */
.version-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
}

.version-toggle:hover {
  border-color: var(--accent);
}

.version-toggle .stage-chevron {
  width: 14px;
  height: 14px;
}

.version-toggle[aria-expanded="true"] .stage-chevron {
  transform: rotate(90deg);
}

.doc-versions-row td {
  background: var(--surface-sunken);
}

.version-list {
  list-style: none;
  margin: var(--space-1) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.version-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.version-num {
  color: var(--ink-faint);
}

.version-meta {
  color: var(--ink-faint);
  font-size: var(--text-sm);
}

table.data tbody tr.row-link {
  cursor: pointer;
}

/* FB-02: tint the whole operations row with its aggregate urgency colour.
   FB-01: the same colour drives the Status semaphore light (overriding the
   lifecycle data-status colour, which now only carries the label text). */
tr.row-link[data-urgency="overdue"] { background: var(--row-overdue); }
tr.row-link[data-urgency="overdue"]:hover { background: var(--row-overdue-hover); }
tr.row-link[data-urgency="soon"] { background: var(--row-soon); }
tr.row-link[data-urgency="soon"]:hover { background: var(--row-soon-hover); }
tr.row-link[data-urgency="active"] { background: var(--row-active); }
tr.row-link[data-urgency="active"]:hover { background: var(--row-active-hover); }
tr.row-link[data-urgency="done"] { background: var(--row-done); }
tr.row-link[data-urgency="done"]:hover { background: var(--row-done-hover); }
tr.row-link[data-urgency="cancelled"] { background: var(--row-cancelled); }
tr.row-link[data-urgency="cancelled"]:hover { background: var(--row-cancelled-hover); }

tr.row-link[data-urgency="overdue"] .status .light {
  background: var(--status-pending);
  box-shadow: 0 0 0 3px var(--status-pending-soft);
}

tr.row-link[data-urgency="soon"] .status .light {
  background: var(--status-progress);
  box-shadow: 0 0 0 3px var(--status-progress-soft);
}

tr.row-link[data-urgency="active"] .status .light {
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

tr.row-link[data-urgency="done"] .status .light {
  background: var(--status-done);
  box-shadow: 0 0 0 3px var(--status-done-soft);
}

tr.row-link[data-urgency="cancelled"] .status .light {
  background: var(--status-na);
  box-shadow: 0 0 0 3px var(--status-na-soft);
}

/* The reference of a cancelled file stops competing with the live ones: it is
   still a link and still legible, just no longer something to act on. */
tr.row-link[data-urgency="cancelled"] .ref,
tr.row-link[data-urgency="cancelled"] .stage-cell {
  color: var(--ink-soft);
}

table.data .ref {
  font-weight: 700;
  color: var(--ink);
}

/* XC-09: the reference cell is a real link (keyboard / open-in-new-tab), but it
   reads as the plain bold reference until hovered or focused. */
table.data a.ref-link {
  text-decoration: none;
}

table.data a.ref-link:hover,
table.data a.ref-link:focus-visible {
  text-decoration: underline;
  color: var(--accent);
}

table.data .muted {
  color: var(--ink-faint);
}

.files-toolbar,
.notes-toolbar {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.note-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
}

.note {
  padding-block: var(--space-4);
  padding-inline: var(--space-3) 0;
  border-bottom: 1px solid var(--border-subtle);
  /* Reserved so a note does not shift sideways when it turns read. */
  border-left: 3px solid transparent;
}

.note:last-child { border-bottom: none; }

.note-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.note-author {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--ink);
}

.note-head .badge-pill {
  margin-left: auto;
}

.note-date {
  display: block;
  margin-block: 2px var(--space-2);
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.note-text {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  white-space: pre-wrap;
}

.card-empty {
  margin: 0;
  padding: var(--space-6) var(--space-4);
  text-align: center;
  background: var(--row-active);
  border: 1px dashed var(--accent-soft);
  border-radius: var(--radius);
  color: var(--ink-faint);
}

/* Unread note (NOTE-04): accent left border + a dot before the author. */
.note.unread {
  border-left-color: var(--accent);
}

.note-unread {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
}

/* Threaded replies (NOTE-05). */
.note-replies {
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0 0 0 var(--space-4);
  border-left: 2px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.note-reply .note-text {
  font-size: var(--text-sm);
}

.note-foot {
  margin-top: var(--space-2);
}

.note-reply-btn {
  padding: 0;
  border: none;
  background: none;
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
}

.note-reply-btn:hover {
  text-decoration: underline;
}

.note-reply-form {
  margin-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.note-reply-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
}

.badge-pill.important {
  background: var(--status-progress-soft);
  color: var(--status-progress);
}

.file-link {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-weight: 700;
  color: var(--accent);
  cursor: pointer;
  text-align: left;
}

.file-link:hover {
  text-decoration: underline;
}

/* Unread-notes marker */
.notes-flag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--accent);
  font-weight: 700;
  font-size: var(--text-xs);
}

/* ---- States ---- */

.state {
  display: none;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-8) var(--space-5);
  color: var(--ink-faint);
}

.state .glyph {
  color: var(--ink-muted);
}

.state h3 {
  font-size: var(--text-md);
  color: var(--ink);
}

.spinner {
  width: 28px;
  height: 28px;
  border: 3px solid var(--border-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ---- Skip to content (XC-10) ---- */

.skip-link {
  position: fixed;
  top: var(--space-2);
  left: var(--space-2);
  z-index: 200;
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: #fff;
  border-radius: var(--radius-sm);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-150%);
  transition: transform var(--dur-fast) var(--ease);
}

.skip-link:focus-visible,
.skip-link:focus {
  transform: translateY(0);
  outline: 2px solid var(--accent-strong, var(--accent));
  outline-offset: 2px;
}

/* XC-10: honour prefers-reduced-motion app-wide — the spinner stops spinning,
   modal / drawer / daterange transitions and the stage & chevron rotations all
   resolve instantly. Toasts stay announced via aria-live. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---- Placeholder (page wired into the flow but not built yet) ---- */

.placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-3);
  min-height: 320px;
  padding: var(--space-8) var(--space-5);
  background: var(--surface);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  color: var(--ink-faint);
}

.placeholder .glyph {
  color: var(--ink-muted);
}

.placeholder h2 {
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--ink);
}

.placeholder p {
  max-width: 46ch;
  font-size: var(--text-sm);
}

/* Pagination */
.pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--border);
  border-bottom-left-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
  font-size: var(--text-sm);
  color: var(--ink-faint);
  flex-wrap: wrap;
}

.pagination .pages {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.page-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.page-btn:hover:not(:disabled):not(.active) {
  background: var(--surface-sunken);
}

.page-btn.active {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

.page-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.page-ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  color: var(--ink-faint);
}

.page-info {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.page-size {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 600;
  color: var(--ink-muted);
}

.page-size .select {
  height: 30px;
  min-width: 0;
  padding: 0 var(--space-2);
  font-size: var(--text-sm);
}

.page-indicator {
  padding: 0 var(--space-2);
  font-variant-numeric: tabular-nums;
}

/* ---- Same table, stacked into cards on tablet + mobile ---- */

/* The wide table can't fit narrow screens, so each row stacks into a card and
   every cell shows its column name via data-label. Same <table>, no duplicate markup. */
@media (max-width: 991px) {
  .table-wrap {
    border: none;
    background: transparent;
  }

  table.data {
    min-width: 0;
  }

  table.data thead {
    display: none; /* column names move onto each cell (data-label) */
  }

  table.data tbody,
  table.data tfoot,
  table.data tr,
  table.data td {
    display: block;
  }

  table.data tr {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--space-1) var(--space-4);
    margin-bottom: var(--space-3);
  }

  table.data td {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border-subtle);
  }

  table.data tr td:last-child {
    border-bottom: none;
  }

  table.data td::before {
    content: attr(data-label);
    margin-right: auto;
    flex-shrink: 0;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--ink-faint);
  }
}

/* On mobile the pagination groups wrap; centring them instead of spreading them
   keeps each one from sticking to a different edge. */
@media (max-width: 767px) {
  .pagination {
    justify-content: center;
  }
}

/* ---- Modal (native dialog: backdrop, focus and Esc for free) ---- */

.modal {
  width: min(580px, calc(100vw - 2 * var(--space-4)));
  max-height: calc(100vh - 2 * var(--space-6));
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
    overlay var(--dur) var(--ease) allow-discrete, display var(--dur) var(--ease) allow-discrete;
}

.modal.wide {
  width: min(960px, calc(100vw - 2 * var(--space-5)));
}

.modal[open] {
  opacity: 1;
  transform: none;
}

@starting-style {
  .modal[open] {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
  }
}

.modal::backdrop {
  background: hsl(207 46% 13% / 0.45);
  opacity: 0;
  transition: opacity var(--dur) var(--ease),
    overlay var(--dur) var(--ease) allow-discrete, display var(--dur) var(--ease) allow-discrete;
}

.modal[open]::backdrop {
  opacity: 1;
}

@starting-style {
  .modal[open]::backdrop {
    opacity: 0;
  }
}

.modal form,
.modal-shell {
  display: flex;
  flex-direction: column;
  max-height: inherit;
}

/* A modal whose head / body are direct children (no form or .modal-shell wrapper)
   needs that column flex on the dialog itself — without it .modal-body can't
   scroll and a long list is clipped by the dialog's overflow. Scoped to [open] so
   a closed dialog keeps its display: none. */
.modal[open]:has(> .modal-body) {
  display: flex;
  flex-direction: column;
}

.modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.modal-head .icon-button {
  color: var(--status-pending);
}

.modal-head .icon-button:hover {
  color: var(--status-pending);
}

.modal-head h2 {
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--ink);
}

.modal-head p {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

.modal-body {
  padding: var(--space-5);
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

.modal-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border);
  background: var(--surface-sunken);
  flex-shrink: 0;
}

/* ---- Forms: required fields, per-field and general errors ---- */

.req::after {
  content: " *";
  color: var(--status-pending);
}

.field .field-error {
  display: none;
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--status-pending);
}

.field .field-hint {
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.field .field-warn {
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--status-progress);
}

.field.invalid .input,
.field.invalid .select {
  border-color: var(--status-pending);
}

.field.invalid .field-error {
  display: block;
}

.field.invalid .field-hint {
  display: none;
}

.checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--ink-soft);
  cursor: pointer;
}

.checkbox input {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}

/* A field whose value is derived, not typed: reads as text where an input
   would sit, without pretending to be editable. */
.field-readout {
  margin: 0;
  padding: 9px 0;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
}

/* A set of checkboxes read as one field (the offices a person supervises). */
.check-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) 0;
}

.check-group .checkbox {
  font-size: var(--text-sm);
}

.input-with-toggle {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.input-with-toggle .input {
  flex: 1;
}

.input-with-toggle .checkbox {
  flex-shrink: 0;
  font-size: var(--text-xs);
  font-weight: 600;
}

.form-error {
  margin-bottom: var(--space-4);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--status-pending-soft);
  color: var(--status-pending);
  font-size: var(--text-sm);
  font-weight: 600;
}

.invoice-calc {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: 600;
}

/* FB8-12: load lines of an invoice — one row per partial load (qty × rate). */
.invoice-lines {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.invoice-line {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto auto;
  align-items: center;
  gap: var(--space-2);
}

.invoice-line-sep {
  color: var(--ink-faint);
}

.invoice-line-total {
  min-width: 9ch;
  text-align: right;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-soft);
}

/* The lines behind a registered freight invoice, under its concept, and the
   contract options that were fixed but not executed (FB9-08). */
.invoice-line-note,
.qty-breakdown,
.summary-alts,
.summary-note,
.declared-note,
.cancel-note,
.terms-note {
  display: block;
  margin-top: 2px;
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--ink-faint);
}

/* FB18-03: options that carry a comment can't read as "A or B" on one line — the
   comment is what tells them apart, so each option is its own block. */
.summary-options {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.summary-option {
  display: block;
}

/* C-14: the option the file was billed by leads the list and the ones it wasn't
   fall back — the panel answers "what does this file invoice by" before it
   answers "what did the contract allow". */
.summary-option:not(.is-applied) {
  color: var(--ink-faint);
}

.summary-tag {
  margin-left: var(--space-2);
  padding: 1px var(--space-2);
  border-radius: var(--radius-sm);
  background-color: var(--accent-soft);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--accent);
}

/* Several options and none declared: what reads below is the first one standing
   in, and the panel has to say so rather than look settled. */
.summary-pending {
  display: block;
  margin-bottom: var(--space-1);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--status-pending);
}

/* FB9-08: several port options in the same contract. One grid for the whole list
   so the inputs share a column and every row's action lands in the same lane to
   their right. */
[data-option-list] {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2);
}

.option-row {
  display: contents;
}

/* FB18-03: an option with a comment needs two inputs, so the row stops sharing
   the list's grid and becomes its own: the value keeps the ✕ beside it and the
   comment sits underneath, which is both what it explains and the only layout
   that survives a phone. */
[data-option-list].with-notes {
  grid-template-columns: minmax(0, 1fr);
}

/* The row gap has to clear the focus ring, which is 3px: at 4px the ring of the
   control landed on the comment underneath and the pair looked like it shifted
   every time the field was focused. */
.with-notes .option-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--space-2);
  row-gap: var(--space-2);
}

/* C-14: a money option is one value in three parts — a fixed currency, the
   amount, and the unit it is quoted in — so they are joined into a single
   control instead of three floating in a row. The group spans the column so it
   lines up with the port inputs above it, and the unit is what absorbs the
   slack — the amount stays the size of the figure it holds, because a rate is
   five characters and a box the width of a port name only puts distance between
   it and the currency that qualifies it. Sizing the whole group by its content
   was worse still: it gave every row a different width. */
.option-money {
  display: flex;
  align-items: center;
  width: 100%;
}

.option-money > * {
  border-radius: 0;
}

.option-money > :first-child {
  border-start-start-radius: var(--radius-sm);
  border-end-start-radius: var(--radius-sm);
}

.option-money > :last-child {
  border-start-end-radius: var(--radius-sm);
  border-end-end-radius: var(--radius-sm);
}

/* Adjacent members share one border rather than stacking two. */
.option-money > * + * {
  margin-left: -1px;
}

/* Printed rather than chosen: the desk invoices in one currency. It reads as the
   unit of the figure beside it, so it sits quiet and on the same baseline. */
.option-currency {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border);
  background-color: var(--surface-sunken);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-faint);
}

/* Sized for the figure it holds — a rate to the cent, a lumpsum with its
   thousands — and right-aligned so those cents line up down the list. It never
   grows: a longer figure scrolls inside the box. It gives way only on a narrow
   screen, where the alternative is the unit falling off the row. */
.option-amount {
  flex: 0 1 7rem;
  min-width: 0;
  text-align: right;
}

/* The unit takes the slack, so the group still ends where the port inputs above
   it end. It is the only member that can: the currency is a fixed word and the
   amount is sized to the figure. */
.option-unit {
  flex: 1;
  min-width: 0;
}

/* The focused member has to draw its border over its neighbours, or the shared
   edge hides half the focus ring. */
.option-money .input:focus,
.option-money .select:focus {
  position: relative;
  z-index: 1;
}


/* The comment is subordinate to the value it explains: same column so the pair
   reads as one block, shorter and quieter so it never looks like another rate.
   Its height and type size carry that on their own — the sunken fill it used to
   have is what every disabled control here wears, so the one editable field in
   the row read as the locked one. */
.option-note {
  grid-column: 1;
  height: 32px;
  font-size: var(--text-sm);
}

.option-note::placeholder {
  font-style: italic;
}

/* The gap between two options has to beat the gap inside one, or four inputs in
   a row read as four rates. */
.with-notes .option-row + .option-row {
  margin-top: var(--space-4);
}

/* C-14: marking which option was executed. It rides in its own lane between the
   value and the ✕, so the marks of every row line up and the list reads down the
   column: this one, not those. */
/* C-14: the mark leads the row, which is how a list you pick one from reads
   everywhere else. Boxed and labelled on each row it was a second button beside
   the ✕, and two of them made the group look like four actions instead of one
   choice. Only where the rows share the list's grid: with comments each row is
   its own grid and the list stays single-column. */
[data-option-list].with-pick:not(.with-notes) {
  grid-template-columns: auto minmax(0, 1fr) auto;
}

.with-notes.with-pick .option-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
}

/* The comment explains the value, not the choice, so it sits under the value and
   keeps the mark's column clear — the radios stay a single readable column. */
.with-pick .option-note {
  grid-column: 2 / -1;
}

.option-pick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 38px;
  padding-right: var(--space-1);
  cursor: pointer;
}

.option-pick input {
  width: 17px;
  height: 17px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

/* The checked radio is the whole signal. Tinting the row's controls on top of it
   read as focus, which is the one thing a border in the accent colour already
   means here. */

/* Said once for the list: what the radios decide, and whether it is still
   pending. */
.option-hint {
  grid-column: 1 / -1;
  margin: 0 0 var(--space-1);
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

/* Adding is an action on the whole list, so it rides above it on the label's
   line, flush right. */
.option-head {
  grid-column: 1 / -1;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
}

.option-add {
  margin-left: auto;
}

/* Matches the height of the option it removes. */
.option-remove {
  align-self: stretch;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-faint);
  cursor: pointer;
}

.option-remove:hover {
  border-color: var(--status-pending);
  color: var(--status-pending);
}

/* In the side-label layout of the alta, a control that grows — an option list,
   a resizable textarea — would drag the label to the middle of the field. The
   label stays level with the top of the control instead. */
.form-stacked .field:has([data-option-list], textarea) {
  align-items: start;
}

/* Nudged down to sit on the first line of the box. An option list needs no
   nudge: its own head is that first line, and the side label reads as part of
   it. */
.form-stacked .field:has(textarea) > label {
  padding-top: var(--space-3);
}

@media (max-width: 575px) {
  .form-stacked .field:has(textarea) > label {
    padding-top: 0;
  }
}

/* The option lists are a block of their own inside a form that already has
   fields above them. */
.contract-options {
  margin-top: var(--space-4);
}

/* A modal that splits its fields into more than one grid still reads as one
   form: consecutive grids keep the gap the fields inside them have, or the
   first field of the next block sits on top of the last one above it. */
.modal .form-grid + .form-grid {
  margin-top: var(--space-4);
}

@media (max-width: 575px) {
  .invoice-line {
    grid-template-columns: 1fr auto auto;
  }

  .invoice-line-sep {
    display: none;
  }

  .invoice-line-total {
    grid-column: 1 / -1;
    text-align: left;
  }
}

.hint {
  margin-top: var(--space-4);
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

.form-panel {
  width: 100%;
  max-width: 620px;
  margin-inline: auto;
}

.form-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border);
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
}

.form-grid .span-2 {
  grid-column: span 2;
}

.modal .form-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.form-stacked {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.form-stacked .field {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr);
  align-items: center;
  column-gap: var(--space-4);
  row-gap: var(--space-1);
}

.form-stacked .field label {
  justify-self: start;
}

/* FB3-01: operation-number builder — derived country-year prefix and type
   suffix around the editable correlative number suggested at creation. */
.ref-builder {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.ref-prefix,
.ref-suffix {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  white-space: nowrap;
}

.input.ref-number {
  /* Box-sizing is border-box, so the 4 digits need the input's own horizontal
     padding added on top — a bare 6ch clips the last digit. */
  width: calc(5ch + 2 * var(--space-3));
  text-align: center;
}

.form-stacked .field .field-error,
.form-stacked .field .field-hint,
.form-stacked .field .field-warn {
  grid-column: 2;
}

@media (max-width: 575px) {
  .form-stacked .field {
    grid-template-columns: 1fr;
    align-items: stretch;
    row-gap: var(--space-1);
  }

  .form-stacked .field .field-error,
  .form-stacked .field .field-hint,
  .form-stacked .field .field-warn {
    grid-column: 1;
  }
}

@media (max-width: 991px) {
  .form-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Phones: a 2-column grid is too cramped in a narrow modal — stack to one. */
@media (max-width: 575px) {
  .form-grid,
  .modal .form-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 575px) {
  .form-grid {
    grid-template-columns: 1fr;
  }

  .form-grid .span-2 {
    grid-column: span 1;
  }
}

/* ---- Contract-type selector (wizard step 1) ---- */

.type-picker {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.type-option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

.type-option:hover {
  border-color: var(--border-strong);
  background: var(--surface-sunken);
}

.type-option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.type-option::before {
  content: "";
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  border: 2px solid var(--border-strong);
  border-radius: 50%;
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}

.type-option:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.type-option:has(input:checked)::before {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 4px var(--accent);
}

.type-option:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.type-option-name {
  display: block;
  font-weight: 600;
  color: var(--ink);
}

.type-option-desc {
  display: block;
  margin-top: 2px;
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

/* ---- Panel (surface card for settings sections and detail blocks) ---- */

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.panel-head {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border);
}

.panel-head h2 {
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--ink);
}

.panel-head p {
  margin-top: 2px;
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

.panel-body {
  padding: var(--space-5);
}

/* ---- Toggle switch ---- */

.switch {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
  flex-shrink: 0;
}

.switch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.switch .track {
  position: absolute;
  inset: 0;
  background: var(--ink-muted);
  border-radius: var(--radius-pill);
  transition: background var(--dur-fast) var(--ease);
}

.switch .knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  background: #fff;
  border-radius: 50%;
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-fast) var(--ease);
}

.switch input:checked + .track {
  background: var(--accent);
}

.switch input:checked ~ .knob {
  transform: translateX(18px);
}

.switch input:focus-visible + .track {
  box-shadow: 0 0 0 3px var(--focus-ring);
}

.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-subtle);
}

.toggle-row:first-child {
  padding-top: 0;
}

/* A toggle row visually detached from the block above it (e.g. after a form grid) */
.toggle-row.detached {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

.toggle-row:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.toggle-name {
  font-weight: 600;
  color: var(--ink);
}

.toggle-desc {
  margin-top: 2px;
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

/* ---- Per-type notification channel selector ---- */

.notif-channels {
  display: inline-flex;
  gap: var(--space-2);
  flex-shrink: 0;
}

.channel-opt {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px 5px 9px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink-muted);
  cursor: pointer;
  user-select: none;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.channel-opt input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  margin: 0;
}

.channel-icon {
  width: 15px;
  height: 15px;
}

.channel-opt:hover {
  border-color: var(--border-strong, var(--ink-muted));
}

.channel-opt:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}

.channel-opt:has(input:focus-visible) {
  box-shadow: 0 0 0 3px var(--focus-ring);
}

@media (max-width: 520px) {
  .toggle-row {
    flex-wrap: wrap;
  }
  .notif-channels {
    width: 100%;
  }
}

/* ---- Segmented control ---- */

.segmented {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.segment {
  position: relative;
}

.segment input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.segment span {
  display: block;
  padding: 5px var(--space-4);
  border-radius: 4px;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-faint);
  cursor: pointer;
}

.segment:has(input:checked) span {
  background: var(--surface);
  color: var(--accent);
  box-shadow: var(--shadow-sm);
}

.segment:has(input:focus-visible) span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---- Settings layout: sticky section nav + stacked panels ---- */

.settings-layout {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}

.settings-nav {
  position: sticky;
  top: 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.settings-actions {
  position: sticky;
  bottom: 0;
  z-index: 2;
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin: var(--space-5) calc(-1 * var(--space-5)) 0;
  padding: var(--space-4) var(--space-5);
  background: var(--surface);
  border-top: 1px solid var(--border);
  box-shadow: 0 -2px 8px hsl(207 40% 20% / 0.06);
}

.content:has(.settings-actions) {
  padding-bottom: 0;
}

.settings-nav-link {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: 600;
}

.settings-nav-link:hover {
  background: var(--surface-sunken);
  color: var(--ink);
}

.settings-panels {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

/* The account row inside the profile panel */
.account-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.account-row .avatar {
  width: 56px;
  height: 56px;
  font-size: var(--text-md);
}

.account-name {
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--ink);
}

.account-role {
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

@media (max-width: 991px) {
  .settings-layout {
    grid-template-columns: 1fr;
  }

  /* On narrow screens the section nav becomes a horizontal scroll strip */
  .settings-nav {
    position: static;
    flex-direction: row;
    gap: var(--space-1);
    overflow-x: auto;
    padding-bottom: var(--space-2);
  }

  .settings-nav-link {
    white-space: nowrap;
  }
}

@media (max-width: 767px) {
  .settings-actions {
    margin: var(--space-5) calc(-1 * var(--space-4)) 0;
    padding: var(--space-4);
  }
}

/* ---- Operation detail ---- */

.detail-head {
  position: sticky;
  top: 0;
  z-index: 5;
  margin-bottom: var(--space-4);
  padding: var(--space-2) 0 var(--space-3);
  background: var(--canvas);
}

.breadcrumb {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
}

.breadcrumb a {
  color: var(--ink-faint);
}

.breadcrumb a:hover {
  color: var(--accent);
}

.breadcrumb-sep {
  color: var(--ink-faint);
}

.breadcrumb-current {
  color: var(--ink);
}

.detail-title-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.detail-title-row h1 {
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.detail-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* On small screens the actions wrap onto their own full-width line and shrink
   to fit, instead of forcing a horizontal scroll. */
@media (max-width: 767px) {
  .detail-actions {
    margin-left: 0;
    width: 100%;
  }
  .detail-actions .btn {
    height: 30px;
    padding: 0 var(--space-3);
    font-size: var(--text-sm);
  }
  .detail-actions .btn.icon-only {
    flex: 1;
    height: 46px;
    width: auto;
    padding: 0;
  }
}

/* ---- Custom dropdown (styled replacement for the native select popup) ---- */

.dd {
  position: relative;
  display: inline-flex;
}

.dd-native {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.dd-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 38px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

.dd-toggle:hover {
  border-color: var(--border-strong);
}

.dd-open .dd-toggle {
  border-color: var(--accent);
}

.dd-caret {
  flex-shrink: 0;
  margin-left: var(--space-1);
  color: var(--ink-faint);
  transition: transform var(--dur-fast) var(--ease);
}

.dd-open .dd-caret {
  transform: rotate(180deg);
}

.dd-menu {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 100%;
  z-index: 50;
  padding: var(--space-1);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}

.dd-open .dd-menu {
  display: block;
}

.dd-option {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.dd-option:hover {
  background: var(--surface-sunken);
}

.dd-option.selected {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

/* DET-09: active risk badges in the header. */
.head-risks {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  flex-wrap: wrap;
}

.type-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.summary-list {
  display: flex;
  flex-direction: column;
}

.summary-list .summary-item {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border-subtle);
}

.summary-list .summary-item:first-child {
  padding-top: 0;
}

.summary-list .summary-item:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.summary-item {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  min-width: 0;
}

.summary-item .k {
  flex-shrink: 0;
  width: 108px;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.summary-item .v {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
  min-width: 0;
  /* Long unbroken values (emails, references) must wrap instead of being clipped
     by the narrow data column. */
  overflow-wrap: anywhere;
}

.detail-layout {
  display: grid;
  /* FB4-01: narrowed from 340px (that width was for the calendar, now moved to
     the main column) — the data panel and My notes card read fine at 300px. */
  grid-template-columns: 350px minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  margin-top: var(--space-4);
}

.detail-col-data,
.detail-col-main {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

@media (max-width: 991px) {
  .detail-layout {
    grid-template-columns: 1fr;
  }
}

.detail-cards {
  display: grid;
  /* 280px min: the calendar's header (title + month nav) has a ~269px intrinsic
     width, so a narrower track would overflow the card at some breakpoints. */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-4);
}

/* FB4-01: Deadlines / Calendar / Risk row above the tabs — the cards share
   a height (stretch to the tallest, which is the calendar). */
.detail-cards-top {
  align-items: stretch;
}

/* FB6-01: ETA notices reuse the My Day day-item look — the operator's daily
   status updates per file, each with the left accent bar. Text wraps (unlike the
   compact My Day rows) since the update itself is the content. */
.eta-list .day-item {
  position: relative;
  align-items: flex-start;
  padding-left: var(--space-3);
}
.eta-list .day-item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 55%;
  border-radius: var(--radius-pill);
  background: var(--status-progress);
}
.eta-item-text {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink);
}
.eta-list .day-item-meta { white-space: normal; overflow: visible; }

/* ---- Time Charter tab (XC-13/14/15): hire, delivery, surveys ---- */
.danger-text { color: var(--status-pending); font-weight: 600; }

[data-tab-panel="hire"] > .panel + .detail-cards,
[data-tab-panel="hire"] > .detail-cards + .panel {
  margin-top: var(--space-4);
}

.tc-survey {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}
.tc-survey:last-child { border-bottom: 0; }

.tc-survey-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.tc-survey-meta {
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

.tc-offhire {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

.tc-offhire-head {
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.tc-offhire-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
}
.tc-offhire-row:last-child { border-bottom: 0; }

/* ---- Calendar card (FB-08) ---- */
.cal-nav {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.cal-caption {
  font-size: var(--text-sm);
  font-weight: 600;
  min-width: 8.5em;
  text-align: center;
}

.cal-nav .icon-button {
  width: 24px;
  height: 24px;
  padding: 0;
}

/* Reserve the tallest-month height so the card doesn't jump on 5-row months. */
.panel-body:has(> [data-calendar]),
.panel-body:has(> [data-month-calendar]) {
  min-height: 230px;
}

/* Calendar day hover summary (Bootstrap tooltip, html). Wider than the default
   200px so "task · N operations" fits on one line. */
.tooltip:has(.cal-tip) { --bs-tooltip-max-width: 320px; }

/* max-content: the tooltip sizes to its longest line (capped by the inner's
   max-width) instead of collapsing to Bootstrap's break-word measure. */
.cal-tip {
  text-align: left;
  width: max-content;
  max-width: 100%;
}
.cal-tip-head {
  font-weight: 700;
  margin-bottom: 4px;
}
/* Inline flow (not flex) so the line measures its full width and only wraps when
   it really exceeds the tooltip; the dot hangs outside the text block. */
.cal-tip-item {
  padding-left: 12px;
  text-indent: -12px;
}
.cal-tip-item::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 6px;
  vertical-align: 1px;
  border-radius: 50%;
  background: var(--status-na);
}
.cal-tip-overdue::before { background: var(--status-pending); }
.cal-tip-soon::before { background: var(--status-progress); }
.cal-tip-ok::before { background: var(--status-done); }

/* Tally line under the date: how the day's deadlines split by urgency. */
.cal-tip-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin-bottom: 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid hsl(0 0% 100% / 0.15);
  font-size: var(--text-xs);
  font-weight: 600;
}

.cal-tip-tally {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.cal-tip-tally::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--status-na);
}

/* Two classes so the urgency colour wins over the tally's neutral default. */
.cal-tip-tally.cal-tip-overdue::before { background: var(--status-pending); }
.cal-tip-tally.cal-tip-soon::before { background: var(--status-progress); }
.cal-tip-tally.cal-tip-ok::before { background: var(--status-done); }

/* How many operations carry that task (or its reference when it's just one) —
   never split off its own line. */
.cal-tip-count {
  opacity: 0.7;
  white-space: nowrap;
}

.cal-tip-rest::before { opacity: 0.5; }

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  text-align: center;
}

.cal-dow {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-faint);
  padding-bottom: 2px;
}

.cal-day {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Shorter than square rows so the calendar doesn't push the tabs far down. */
  height: 26px;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  border-radius: var(--radius-sm);
}

/* Padding cells hold a row's height so an all-empty 6th week doesn't collapse
   (the calendar always renders 6 weeks to keep every month the same height). */
.cal-pad { height: 26px; }

/* A day with a deadline is highlighted directly (tinted cell + coloured number
   by urgency) instead of a separate dot. */
.cal-day.has-deadline { font-weight: 700; }
.cal-day[data-state="overdue"] { background: var(--status-pending-soft); color: var(--status-pending); }
.cal-day[data-state="soon"] { background: var(--status-progress-soft); color: var(--status-progress); }
.cal-day[data-state="ok"] { background: var(--status-done-soft); color: var(--status-done); }

/* Today wins the highlight. */
.cal-day.is-today {
  background: var(--accent-soft);
  color: var(--accent);
}

/* ---- FB7-04: manual events, day drill-in and legend ---- */
/* Day cells are buttons now (clickable drill-in) — reset button chrome. A plain
   day keeps a soft blue-grey fill (not the neutral native button grey). */
.cal-day {
  appearance: none;
  border: 0;
  font-family: inherit;
  cursor: default;
  background: #f3f8fc;
}
.cal-day.is-clickable {
  cursor: pointer;
  transition: filter var(--dur-fast) var(--ease);
}

/* No grey ring on hover: a day that already carries a tint just deepens it, and an
   empty day washes over to the navy accent. Keyboard focus keeps the global ring. */
.cal-day.is-clickable:hover { filter: brightness(0.96); }

.cal-day.is-clickable:not([data-state]):hover {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Manual event days pick up the navy accent when they carry no deadline. */
.cal-day[data-state="event"] { background: var(--accent-soft); color: var(--accent); font-weight: 700; }

.cal-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
}
.cal-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
.cal-legend-item::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--status-na);
}
.cal-legend.cal-tip-overdue::before,
.cal-legend-item.cal-tip-overdue::before { background: var(--status-pending); }
.cal-legend-item.cal-tip-soon::before { background: var(--status-progress); }
.cal-legend-item.cal-tip-ok::before { background: var(--status-done); }
.cal-legend-item.cal-legend-event::before { background: var(--accent); }

.cal-tip-event::before { background: #fff; }

/* Day drill-in modal: list of the day's deadlines and events + add form. */
.cal-day-list {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.cal-day-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-sunken);
}
.cal-day-item-title {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.cal-day-item-note {
  font-weight: 500;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  align-self: flex-start;
}

/* FB8-01: in My day the note is the file the deadline belongs to — a link. */
a.cal-day-item-note {
  text-decoration: none;
}
a.cal-day-item-note:hover,
a.cal-day-item-note:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}
.cal-day-item-tag {
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}
.cal-day-remove {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 2px;
  border-radius: var(--radius-sm);
  display: inline-flex;
}
.cal-day-remove:hover { color: var(--status-pending); background: var(--status-pending-soft); }
.cal-day-empty {
  padding: var(--space-4);
  text-align: center;
}
.deadline-dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--status-na);
}
.deadline-dot[data-state="overdue"] { background: var(--status-pending); }
.deadline-dot[data-state="soon"] { background: var(--status-progress); }
.deadline-dot[data-state="ok"] { background: var(--status-done); }
.deadline-dot[data-state="event"] { background: var(--accent); }

.cal-day-add {
  border-top: 1px solid var(--border);
  padding-top: var(--space-3);
}
.cal-day-add-title {
  font-size: var(--text-sm);
  margin: 0 0 var(--space-3);
}
.cal-day-add-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-3);
}

/* FB7-03: inline edit affordance next to a summary value (loaded quantity). */
.link-edit {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 1px;
  margin-left: 6px;
  border-radius: var(--radius-sm);
  display: inline-flex;
  vertical-align: -2px;
}
.link-edit:hover { color: var(--accent); background: var(--accent-soft); }

/* Workflow stepper — the 11-stage file tracker */
.workflow {
  list-style: none;
  margin: 0;
  padding: 0;
}

.stage {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--space-3);
}

.stage-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.stage-marker {
  width: 16px;
  height: 16px;
  margin-top: 2px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  background: var(--surface);
  flex-shrink: 0;
}

/* Connector line down to the next stage */
.stage-rail::after {
  content: "";
  flex: 1;
  width: 2px;
  margin: var(--space-1) 0;
  background: var(--border);
}

.stage:last-child .stage-rail::after {
  display: none;
}

.stage-body {
  padding-bottom: var(--space-5);
  min-width: 0;
}

.stage:last-child .stage-body {
  padding-bottom: 0;
}

.stage-name {
  font-weight: 600;
  color: var(--ink);
}

.stage-meta {
  margin-top: 2px;
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

.stage-status {
  padding-top: 2px;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}

.stage[data-status="done"] .stage-marker {
  background: var(--status-done);
  border-color: var(--status-done);
}

.stage[data-status="progress"] .stage-marker {
  background: var(--status-progress);
  border-color: var(--status-progress);
  box-shadow: 0 0 0 3px var(--status-progress-soft);
}

.stage[data-status="pending"] .stage-marker {
  border-color: var(--status-pending);
}

.stage[data-status="done"] .stage-status {
  color: var(--status-done);
}

.stage[data-status="progress"] .stage-status {
  color: var(--status-progress);
}

.stage[data-status="pending"] .stage-status,
.stage[data-status="na"] .stage-status {
  color: var(--ink-muted);
}

.stage[data-status="na"] .stage-name {
  color: var(--ink-muted);
}

/* Workflow — interactive stage rows (extends the stepper above) */
.stage {
  grid-template-columns: auto minmax(0, 1fr);
}

.stage-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: 0;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
}

.stage-headline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  flex: 1;
}

.stage-title {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  flex: 0 1 auto;
}

.stage-num {
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

.stage-head .stage-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tag {
  flex-shrink: 0;
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  color: var(--ink-faint);
}

.stage-marks {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  flex-shrink: 0;
}

.stage-mark {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px 2px 6px;
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1.4;
  background: var(--accent-soft);
  color: var(--accent);
}

.stage-mark[data-mark="attachment"] {
  background: var(--risk-soft);
  color: var(--risk);
}

.stage-mark-icon {
  flex-shrink: 0;
}

.stage-trailing {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-shrink: 0;
}

.stage-when {
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

.stage-chevron {
  color: var(--ink-faint);
  transition: transform var(--dur-fast) var(--ease);
}

.stage-head[aria-expanded="true"] .stage-chevron {
  transform: rotate(90deg);
}

.stage-sub {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-1);
  font-size: var(--text-sm);
}

.stage-by {
  color: var(--ink-faint);
}

.stage[data-status="na"] .stage-marker {
  border-color: var(--status-na);
}

.stage-detail {
  margin-top: var(--space-3);
  padding: var(--space-4);
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
}

.stage-empty {
  margin: 0;
  font-size: var(--text-sm);
}

.stage-field-label {
  display: block;
  margin-bottom: var(--space-1);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.stage-justification {
  margin: 0 0 var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--status-na-soft);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.stage-log {
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.stage-log-item {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.stage-log-text {
  font-size: var(--text-sm);
  color: var(--ink);
}

.stage-log-meta {
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.stage-status-picker {
  height: auto;
  min-width: 0;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent);
  border-radius: var(--radius-sm);
}

.stage-status-picker:hover {
  background: var(--surface);
  border-color: var(--border-strong);
}

.stage-status-picker::picker-icon {
  background-color: var(--accent);
}

.stage-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.stage-tools-right {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-left: auto;
}

.stage-tool {
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent);
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.stage-tool:hover {
  background: var(--surface);
  border-color: var(--border-strong);
}

.stage-tool.danger {
  color: var(--status-pending);
}

.stage-tool.danger:hover {
  border-color: var(--status-pending);
}

/* Footer: primary action + overflow (kebab) menu. */
.stage-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.stage-menu {
  position: relative;
  display: inline-flex;
}

.stage-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-1);
  width: 30px;
  height: 30px;
  color: var(--ink-soft);
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.stage-menu-toggle:hover,
.stage-menu.is-open .stage-menu-toggle {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--ink);
}

.stage-menu-list {
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  /* Below the sticky detail header (z-index 5) and topbar (20) so it slides
     under them instead of covering the title / action bar, but above the
     surrounding stage rows. */
  z-index: 4;
  min-width: 176px;
  display: flex;
  flex-direction: column;
  padding: var(--space-1);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}

.stage-menu-item {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  text-align: left;
  color: var(--ink);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.stage-menu-item:hover {
  background: var(--surface);
}

.stage-menu-item.danger {
  color: var(--status-pending);
}

/* Small caption grouping the deferred-edit selects. */
.stage-props-label {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  align-self: center;
}

/* Mobile: stack the two clusters and lay the properties out on a grid so the
   label and selects don't wrap into a jumble. */
@media (max-width: 767px) {
  /* Collapsed stage header: give the name its own line and let the kind /
     deadline chips wrap below, instead of squeezing the name to nothing and
     overlapping. */
  .stage-headline {
    flex-wrap: wrap;
    row-gap: var(--space-1);
  }

  .stage-title {
    flex: 1 1 100%;
  }

  .stage-head .stage-name {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }

  .stage-trailing {
    align-self: flex-start;
  }

  .stage-tools {
    flex-direction: column;
    align-items: stretch;
  }

  .stage-actions {
    justify-content: space-between;
  }

  .stage-tools-right {
    margin-left: 0;
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
  }

  .stage-props-label {
    grid-column: 1 / -1;
    align-self: start;
  }

  .stage-tools-right .stage-status-picker {
    width: 100%;
  }

  .stage-tools-right [data-status-select],
  .stage-tools-right [data-save-changes] {
    grid-column: 1 / -1;
  }

  /* The kebab sits at the right edge on mobile — open the menu leftward so it
     stays on screen instead of overflowing off the right. */
  .stage-menu-list {
    left: auto;
    right: 0;
  }
}

.stage-comments {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: 0;
}

.stage-files {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: 0;
}

.stage-comment {
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.stage-comment-head {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.stage-comment-author {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
}

.stage-comment-date {
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.stage-comment-text {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.stage-file {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.stage-file-icon {
  flex-shrink: 0;
  color: var(--ink-faint);
}

.stage-file-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.stage-file-name {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
}

.stage-file-meta {
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-5);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--ink-faint);
  font-size: var(--text-sm);
  text-align: center;
  cursor: pointer;
}

.dropzone strong {
  color: var(--accent);
}

.dropzone:hover,
.dropzone.dragover {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--ink-soft);
}

.dropzone-hint {
  font-size: var(--text-xs);
}

.file-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  align-self: flex-start;
  padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  font-size: var(--text-sm);
}

.file-chip-remove {
  display: inline-flex;
  padding: 0;
  color: var(--ink-faint);
  background: none;
  border: 0;
  cursor: pointer;
}

.file-chip-remove:hover {
  color: var(--ink);
}

/* Counterparty documents list (FB3-04) */
.doc-list {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.doc-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

.doc-icon {
  display: inline-flex;
  color: var(--ink-faint);
}

.doc-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}

.doc-name {
  font-weight: 600;
}

.doc-sub {
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.doc-add {
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

.doc-add-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-3);
}

.panel-head-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* The month nav (prev · caption · next · Today) must keep its width; on narrow
   panels it wraps under the title instead of being clipped. */
.panel-head-action:has(.cal-nav) {
  flex-wrap: wrap;
}

.panel-head-action .cal-nav {
  flex: none;
}

@media (max-width: 720px) {
  .panel-head-action:has(.wf-type-field) {
    flex-direction: column;
    align-items: stretch;
  }
  .wf-type-field {
    max-width: none;
  }
  .panel-head-action:has(> [data-rt-new]) {
    flex-direction: column;
    align-items: flex-start;
  }
}

.panel-link {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent);
  background: none;
  border: none;
  cursor: pointer;
}

.panel-link:hover {
  text-decoration: underline;
}

.risk-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.risk-item {
  align-items: flex-start;
  justify-content: space-between;
}

.risk-item-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.risk-note {
  font-weight: 500;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  overflow: hidden;
}

.risk-note-full {
  font-weight: 500;
}

.panel-head-titles {
  min-width: 0;
}

.panel-head-links {
  display: flex;
  gap: var(--space-3);
}

.risk-resolve {
  flex-shrink: 0;
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--risk);
  background: none;
  border: none;
  cursor: pointer;
  text-decoration: underline;
}

textarea.input {
  height: auto;
  min-height: 72px;
  padding: var(--space-2) var(--space-3);
  resize: vertical;
}

.settings-panels .input[readonly] {
  background-color: var(--surface-sunken);
  color: var(--ink-soft);
  cursor: default;
}

/* Risk / info alert box */
.alert {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: 600;
}

.alert.risk {
  background: var(--risk-soft);
  color: var(--risk);
}

/* ---- Toast (global feedback, bottom-right; stacks) ---- */

.toast-stack {
  position: fixed;
  bottom: var(--space-4);
  right: var(--space-4);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: min(360px, calc(100vw - var(--space-4) * 2));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  /* The stack sits over the bottom-right corner, where forms keep their submit
     button. Only the dismiss button takes clicks so a toast never swallows the
     click meant for what it covers. */
  pointer-events: none;
  animation: toast-in 360ms cubic-bezier(0.16, 1, 0.3, 1);
}

.toast.leaving {
  animation: toast-out 240ms var(--ease) forwards;
}

.toast[data-type="success"] { border-left-color: var(--status-done); }
.toast[data-type="error"] { border-left-color: var(--status-pending); }
.toast[data-type="warning"] { border-left-color: var(--status-progress); }
.toast[data-type="info"] { border-left-color: var(--accent); }

.toast-icon {
  flex-shrink: 0;
  margin-top: 1px;
}

.toast[data-type="success"] .toast-icon { color: var(--status-done); }
.toast[data-type="error"] .toast-icon { color: var(--status-pending); }
.toast[data-type="warning"] .toast-icon { color: var(--status-progress); }
.toast[data-type="info"] .toast-icon { color: var(--accent); }

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

.toast-title {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--ink);
}

.toast-message {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.toast-title + .toast-message {
  margin-top: 2px;
}

.toast-close {
  flex-shrink: 0;
  pointer-events: auto;
  display: inline-flex;
  padding: 2px;
  color: var(--ink-faint);
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.toast-close:hover {
  color: var(--ink);
  background: var(--surface-sunken);
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(40px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes toast-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(40px); }
}

@media (max-width: 768px) {
  .toast-stack {
    top: auto;
    bottom: var(--space-4);
    left: var(--space-4);
    right: var(--space-4);
    width: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast {
    animation: toast-in 360ms cubic-bezier(0.16, 1, 0.3, 1);
  }
  .toast.leaving {
    animation: toast-out 240ms var(--ease) forwards;
  }
}

/* ---- Tabs ---- */

.tabs {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-5);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-behavior: smooth;
  touch-action: pan-x;
  --tabs-fade: 28px;
}

.tabs::-webkit-scrollbar {
  display: none;
}

/* Edge fades hint that the strip scrolls; tabs.js toggles at-start / at-end.
   Middle = both edges fade, at a boundary = only the far edge, fits = none. */
.tabs:not(.at-start):not(.at-end) {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--tabs-fade), #000 calc(100% - var(--tabs-fade)), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 var(--tabs-fade), #000 calc(100% - var(--tabs-fade)), transparent 100%);
}

.tabs.at-start:not(.at-end) {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - var(--tabs-fade)), transparent 100%);
  mask-image: linear-gradient(90deg, #000 calc(100% - var(--tabs-fade)), transparent 100%);
}

.tabs:not(.at-start).at-end {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--tabs-fade));
  mask-image: linear-gradient(90deg, transparent 0, #000 var(--tabs-fade));
}

.tab {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-faint);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease);
}

.tab:hover {
  color: var(--ink);
}

.tab[aria-selected="true"] {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.tab:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: -2px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.tab-panel[hidden] {
  display: none;
}

.tab-panel:focus {
  outline: none;
}

/* OPS-07: laycan range filter — one range picker in a single toolbar column,
   with a Clear link that only appears once a range is set. */
.laycan-inputs {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.laycan-inputs .daterange {
  flex: 1 1 0;
  min-width: 0;
}

.laycan-inputs [data-laycan-clear] {
  flex-shrink: 0;
}

/* ---- Date-range picker (own component, Airbnb-style) ---- */

.daterange {
  position: relative;
  width: 100%;
}

.daterange .input {
  width: 100%;
  padding-right: calc(var(--space-4) + 18px);
  cursor: pointer;
}

.daterange-icon {
  position: absolute;
  top: 50%;
  right: var(--space-3);
  transform: translateY(-50%);
  display: flex;
  color: var(--ink-faint);
  pointer-events: none;
}

/* Fixed, not absolute: .content clips its overflow and the field can sit anywhere
   in a toolbar, so the popup is placed by hand (see place() in daterange.js). */
.daterange-pop {
  position: fixed;
  z-index: 50;
  padding: var(--space-4);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.daterange-nav {
  position: absolute;
  top: var(--space-4);
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 24px;
  color: var(--ink-soft);
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.daterange-nav svg {
  pointer-events: none;
}

.daterange-nav.prev { left: var(--space-4); }
.daterange-nav.next { right: var(--space-4); }

.daterange-nav:hover:not(:disabled) {
  background: var(--surface-sunken);
  color: var(--ink);
}

.daterange-nav:disabled {
  opacity: 0.3;
  cursor: default;
}

.daterange-months {
  display: flex;
  gap: var(--space-5);
}

.daterange-month {
  width: 224px;
}

.daterange-caption {
  height: 24px;
  line-height: 24px;
  margin-bottom: var(--space-3);
  text-align: center;
  font-weight: 700;
  color: var(--ink);
}

.daterange-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.daterange-dow {
  padding-bottom: var(--space-2);
  text-align: center;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-faint);
}

.daterange-pad {
  aspect-ratio: 1;
}

.daterange-day {
  position: relative;
  z-index: 0;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  color: var(--ink);
  background: none;
  border: 0;
  cursor: pointer;
}

.daterange-day.is-disabled {
  color: var(--ink-muted);
  cursor: default;
}

.daterange-day.is-today {
  font-weight: 700;
}

.daterange-day:not(.is-disabled):not(.is-endpoint):not(.is-in-range):hover {
  background: var(--surface-sunken);
  border-radius: 50%;
}

/* Range band — grid cells touch, so the soft backgrounds form a continuous strip */
.daterange-day.is-in-range {
  background: var(--accent-soft);
  color: var(--ink);
}

.daterange-day.is-start:not(.is-end) {
  background: linear-gradient(to right, transparent 0 50%, var(--accent-soft) 50% 100%);
}

.daterange-day.is-end:not(.is-start) {
  background: linear-gradient(to left, transparent 0 50%, var(--accent-soft) 50% 100%);
}

.daterange-day.is-endpoint {
  color: var(--accent-ink);
}

.daterange-day.is-endpoint::after {
  content: "";
  position: absolute;
  inset: 2px;
  z-index: -1;
  background: var(--accent);
  border-radius: 50%;
}

/* Modals that host a date picker must not clip the floating calendar popup.
   The foot has a background, so re-round its bottom corners without overflow. */
.modal.has-picker,
.modal.has-picker .modal-body {
  overflow: visible;
}

.modal.has-picker .modal-foot {
  border-bottom-left-radius: var(--radius-lg);
  border-bottom-right-radius: var(--radius-lg);
}

/* Deadline rows in the aside */
.deadline-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.deadline-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

/* FB18-02: how long before, on the right of what has to be declared. Wraps under
   the label on a narrow card instead of squeezing it. */
.deadline-row:has(.deadline-when) {
  flex-wrap: wrap;
}

.deadline-when {
  color: var(--ink-faint);
}

/* The version in force, above the list it describes. */
[data-coa-terms-note] {
  margin: 0 0 var(--space-4);
}

/* FB18-02: the addenda that got the COA to the terms in force. Below the list of
   deadlines and visibly secondary to it — the current terms are what gets read
   every day, the history is what explains them. */
.terms-history {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

.terms-history h3 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

.term-version + .term-version {
  margin-top: var(--space-4);
}

.term-version p {
  margin: 2px 0 0;
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.term-version-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  font-size: var(--text-sm);
}

.term-version-head .label {
  font-weight: 600;
  color: var(--ink);
}

/* The rows of the addendum modal: what has to be declared, how long before, and
   what the countdown hangs off. The ✕ shares the lane the option lists use. */
.term-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 88px minmax(0, 190px) auto;
  align-items: center;
  gap: var(--space-2);
}

.term-row + .term-row {
  margin-top: var(--space-2);
}

[data-coa-terms-add] {
  display: block;
  margin: var(--space-3) 0 var(--space-5);
}

/* On a phone the three fields don't fit on one line, so what has to be declared
   takes the first and its timing the second — with the ✕ still beside the timing
   rather than orphaned on a line of its own. */
@media (max-width: 575px) {
  .term-row {
    grid-template-columns: 88px minmax(0, 1fr) auto;
    row-gap: var(--space-2);
  }

  .term-row [data-term-task] {
    grid-column: 1 / -1;
  }
}

/* FB7-05: "Deadlines not set" banner sits above the workflow stages. */
.ddl-pending {
  margin-bottom: 24px;
}

/* FB7-05: quick "Set deadlines" checklist */
.ddl-checklist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.ddl-check-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.ddl-check-name {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
}

.ddl-check-row .input-with-toggle {
  flex-shrink: 0;
  width: min(320px, 60%);
}

.ddl-check-row.is-na .ddl-check-name,
.ddl-check-row.is-na .daterange {
  opacity: 0.45;
}

.ddl-check-row.is-na .daterange {
  pointer-events: none;
}


/* States rendered directly inside a tab panel (mails / invoicing) or a panel
   body (counterparty file, COA shipments) are visible; the [hidden] ones
   (toggled from JS) stay hidden. */
.tab-panel .state:not([hidden]),
.panel-body .state:not([hidden]) { display: flex; }

/* ---- Invoicing table ---- */
table.data th.num,
table.data td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.data .row-actions {
  text-align: right;
  white-space: nowrap;
}

/* ---- Mails tab (Sedna, read-only) ---- */
.alert.notice {
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  background: var(--accent-soft);
  color: var(--ink);
  font-weight: 400;
}

.alert.notice strong {
  display: block;
  margin-bottom: 2px;
  font-weight: 600;
}

.alert.notice p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.mail-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.mail {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}

.mail-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: none;
  border: 0;
  font: inherit;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
}

.mail-head:hover {
  background: var(--surface-sunken);
}

.mail-subject {
  font-weight: 600;
  font-size: var(--text-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-meta {
  font-size: var(--text-xs);
  color: var(--ink-faint);
  white-space: nowrap;
}

.mail-head[aria-expanded="true"] .stage-chevron {
  transform: rotate(90deg);
}

.mail-body {
  padding: 0 var(--space-4) var(--space-4);
  border-top: 1px solid var(--border-subtle);
}

.mail-recipients {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.mail-recipients .k {
  margin-right: var(--space-1);
  color: var(--ink-faint);
}

.mail-text {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--ink);
}

.mail-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.attach-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--text-xs);
}

.attach-chip .attach-name {
  max-width: 24ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.attach-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
}

.attach-action:hover {
  background: var(--surface-sunken);
  color: var(--accent);
}

/* ---- Attachment preview (mock viewer) ---- */
.attach-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 340px;
  padding: var(--space-4);
  background: var(--surface-sunken);
  border-radius: var(--radius);
}

.attach-preview.is-embed {
  padding: 0;
  overflow: hidden;
}

.attach-embed {
  width: 100%;
  height: 70vh;
  border: 0;
  border-radius: var(--radius);
  background: #fff;
}

.attach-img {
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
  border-radius: var(--radius);
}

.doc-page {
  width: min(100%, 440px);
  padding: var(--space-6) var(--space-6) var(--space-8);
  background: #fff;
  color: hsl(207 30% 20%);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}

.doc-page-title {
  font-size: var(--text-lg);
  font-weight: 700;
}

.doc-page-sub {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: hsl(207 12% 55%);
}

.doc-lines {
  margin-top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.doc-line {
  height: 8px;
  border-radius: var(--radius-pill);
  background: hsl(207 20% 90%);
}

.doc-line.short {
  width: 55%;
}

.img-frame {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-8);
  color: var(--ink-faint);
  font-size: var(--text-sm);
}

/* ---- History tab ---- */
.history-toolbar {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.history {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.history-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-3);
}

.history-dot {
  width: 8px;
  height: 8px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--ink-muted);
}

.history-dot[data-type="status"] { background: var(--accent); }
.history-dot[data-type="risk"] { background: var(--risk); }
.history-dot[data-type="deadline"] { background: var(--urgency-high); }

/* Handover stands out from the round event dots: a squared marker with a halo. */
.history-dot[data-type="handover"] {
  background: var(--accent);
  border-radius: 2px;
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.history-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.history-type {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

.history-when {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* System-generated (cascade / engine) entry marker in the log. */
.history-auto {
  margin-left: var(--space-1);
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}

.history-text {
  margin: 2px 0 0;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--ink);
}

.history-text strong {
  font-weight: 600;
}

.history-empty {
  list-style: none;
}

/* Deep-link target highlight (Mails notice → Job Reference in the header). */
.flash {
  animation: flash-bg 1.2s var(--ease);
}

@keyframes flash-bg {
  0%, 100% { background: transparent; }
  20% { background: var(--accent-soft); }
}

/* ---- Notifications page ---- */
.notif-page-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.notif-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid transparent;
  border-radius: var(--radius-sm);
}

.notif-row.unread {
  border-left-color: var(--accent);
}

.notif-row-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.notif-row-text {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
}

.notif-row:not(.unread) .notif-row-text {
  color: var(--ink-soft);
}

.notif-row-text:hover {
  color: var(--accent);
  text-decoration: underline;
}

.notif-row-text strong {
  font-weight: 700;
}

.notif-row-meta {
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.notif-row-mark {
  width: 10px;
  height: 10px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
}

.notif-row-mark:hover {
  background: var(--accent-hover);
}

/* ---- Mail templates ---- */
.data .row-actions .btn + .btn {
  margin-left: var(--space-2);
}

.tpl-body {
  margin: 0;
  padding: var(--space-4);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--ink);
  white-space: pre-wrap;
}

.tpl-hint {
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
}

.tpl-vars {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.tpl-var {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-soft);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
}

.tpl-var:hover {
  background: var(--surface-sunken);
  color: var(--ink);
}

.panel-note {
  display: block;
  margin-top: 2px;
  font-size: var(--text-xs);
  line-height: 1.4;
}

/* ---- Administration & counterparties ---- */

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

/* A trailing action (e.g. a "New …" button) in a filter toolbar shouldn't grow
   like the filter fields — pin it to natural width and push it to the end. */
.toolbar .toolbar-action {
  grid-column: -2 / -1;
  justify-self: end;
}

@media (max-width: 1100px) {
  .toolbar .toolbar-action {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: row;
    justify-content: flex-end;
    margin-left: 0;
  }
}

@media (max-width: 720px) {
  .toolbar .toolbar-action { justify-self: stretch; justify-content: stretch; }
  .toolbar .toolbar-action .btn { width: 100%; }
}

.panel-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4);
  border-top: 1px solid var(--border);
}

@media (max-width: 720px) {
  .panel-foot {
    flex-direction: column;
  }
  .panel-foot .btn {
    width: 100%;
  }
}

.avatar.sm {
  width: 24px;
  height: 24px;
  font-size: 10px;
}

.user-cell {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.data tr.is-inactive td {
  color: var(--ink-faint);
}

.data tr.is-inactive .avatar {
  filter: grayscale(1);
  opacity: 0.7;
}

/* Roles: read-only statement of what each of the five fixed roles grants. One row
   per rule, so the sentence in the first column is what gets read and the grant
   cells only qualify it — hence the wide first column and the narrow rest. The
   width is for the table layout only; in card mode the cell is full width. */
.role-matrix th:first-child,
.role-matrix td:first-child {
  text-align: left;
  color: var(--ink);
}

@media (min-width: 992px) {
  .role-matrix td:first-child {
    min-width: 22rem;
  }
}

.grant {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--text-xs);
  font-weight: 600;
  white-space: nowrap;
}

/* Workflow config: keep the requirement select and threshold input compact. */
.wf-config .select { min-width: 8rem; }

.wf-threshold {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.wf-threshold .input {
  width: 5rem;
}

.wf-threshold .unit {
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

/* Risk-alert types list */
.rt-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.rt-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-1);
  border-bottom: 1px solid var(--border);
}

.rt-item:last-child {
  border-bottom: none;
}

.rt-item.is-inactive .rt-label {
  color: var(--ink-faint);
  text-decoration: line-through;
}

.rt-order {
  display: inline-flex;
  flex-direction: column;
}

.rt-move {
  width: 22px;
  height: 20px;
  color: var(--ink-faint);
}

.rt-move:disabled {
  opacity: 0.35;
  cursor: default;
}

.rt-label {
  flex: 1;
  font-weight: 600;
}

.rt-actions {
  display: inline-flex;
  gap: var(--space-2);
  white-space: nowrap;
}

/* Inline text button (e.g. "View profile" next to the charterer). */
.link-inline {
  padding: 0;
  border: none;
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: 600;
  cursor: pointer;
}

.link-inline:hover {
  text-decoration: underline;
}

/* Counterparty name rendered as a link to its read-only profile. */
.link-name {
  padding: 0;
  border: none;
  background: none;
  color: var(--accent);
  font: inherit;
  cursor: pointer;
  text-align: left;
}

.link-name:hover {
  text-decoration: underline;
}

/* Read-only charterer profile definition list */
.profile-view {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
}

.profile-view dt {
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--ink-faint);
  margin-bottom: 2px;
}

.profile-view dd {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink);
}

/* ---- My day ---- */

/* My day: the hero image runs full-height behind a transparent topbar. The
   content area is stretched up over the topbar row so its top edge (where the
   hero sits) reaches y=0; the sticky topbar floats above it via its z-index. */
[data-page="my-day"] .content {
  grid-row: 1 / 3;
}

[data-page="my-day"] .topbar {
  background: linear-gradient(rgba(0, 0, 0, 0.65), rgba(0, 0, 0, 0));
  border-bottom: 0;
}

/* Solid fill lives on an overlay so it can fade in: you can't transition
   from a gradient to a flat color, but you can animate this layer's opacity. */
[data-page="my-day"] .topbar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}

[data-page="my-day"].day-scrolled .topbar::before {
  opacity: 1;
}

/* Over the transparent header the default dark icons/labels vanish against the
   image, so paint the controls white. Reverts once the header fades to solid. */
[data-page="my-day"] .topbar .icon-button,
[data-page="my-day"] .topbar .role-switch-label {
  transition: color var(--dur) var(--ease);
}

[data-page="my-day"]:not(.day-scrolled) .topbar .icon-button,
[data-page="my-day"]:not(.day-scrolled) .topbar .role-switch-label {
  color: #fff;
}

/* Over the transparent hero the default light hover/open background makes the
   white icon vanish; use a translucent-white highlight and keep the icon white. */
[data-page="my-day"]:not(.day-scrolled) .topbar .icon-button:hover,
[data-page="my-day"]:not(.day-scrolled) .topbar .icon-button[aria-expanded="true"] {
  background: hsl(0 0% 100% / 0.18);
  color: #fff;
}

/* Warm welcome banner: a full-bleed image band under the topbar. The negative
   margins cancel .content's side padding and .inner's top padding so the image
   reaches the content edges; they track the padding at each breakpoint (see the
   ≤767px rule below) to avoid horizontal overflow. Swap the image below for the
   final artwork — keep the gradient so the greeting stays legible over it. */
.day-hero {
  position: relative;
  margin: calc(-1 * var(--space-5)) calc(-1 * var(--space-5)) var(--space-5);
  padding: var(--space-6) var(--space-5) var(--space-5);
  min-height: 300px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background-image:
    linear-gradient(180deg, hsl(207 46% 13% / 0.30) 0%, hsl(207 46% 13% / 0.80) 100%),
    url("../assets/4.png");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  color: var(--ink-invert);
}

.day-hero .page-head {
  margin-bottom: 4px;
}

.day-hero .page-head .titles h1 {
  color: #fff;
  font-size: var(--text-2xl);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-shadow: 0 1px 12px hsl(207 46% 13% / 0.4);
}

.day-hero .greet-name {
  font-weight: 700;
}

.day-hero .greet-wave {
  font-size: 0.7em;
}

.day-hero .day-hello {
  margin: 0;
  font-size: var(--text-md);
  color: hsl(0 0% 100% / 0.9);
  text-shadow: 0 1px 10px hsl(207 46% 13% / 0.35);
}

.day-hero .tools {
  position: absolute;
  bottom: var(--space-5);
  right: var(--space-5);
  z-index: 5;
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.stat-tile {
  flex: 1 1 160px;
  max-width: 280px;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
  text-decoration: none;
}

.stat-tile[data-tone="danger"] { border-left-color: var(--status-pending); }
.stat-tile[data-tone="warning"] { border-left-color: var(--status-progress); }
.stat-tile[data-tone="risk"] { border-left-color: var(--risk); }

.stat-value {
  font-size: var(--text-xl);
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.stat-tile[data-tone="danger"] .stat-value { color: var(--status-pending); }
.stat-tile[data-tone="warning"] .stat-value { color: var(--status-progress); }
.stat-tile[data-tone="risk"] .stat-value { color: var(--risk); }
/* Untoned tile (Open files): match the value to its navy border. */
.stat-tile:not([data-tone]) .stat-value { color: var(--accent); }

.stat-label {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

[data-page="my-day"] .stat-tile,
[data-page="reports"] .stat-tile {
  flex: 1 1 0;
  max-width: none;
}

/* Banded row of equal-height cards. */
.day-top {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--space-5);
  align-items: stretch;
  margin-bottom: var(--space-5);
}

/* FB8-01: with the overdue card moved beside the calendar, this row holds two. */
.day-top-pair {
  grid-template-columns: 1fr 1fr;
}

.stat-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

.stat-grid .stat-tile {
  justify-content: center;
}

/* FB8-01: the month calendar takes half the width on desktop, with the overdue
   card filling the other half. Both panels stretch to the taller one. */
.day-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
  align-items: stretch;
  margin-bottom: var(--space-5);
}

.day-split > * {
  min-width: 0;
}

/* Both cards read as one band: the shorter panel stretches to the taller one and
   its rows share the extra height instead of leaving a gap under the list. */
.day-split > .panel {
  display: flex;
  flex-direction: column;
}

.day-split > .panel > .panel-body {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.day-split .day-list {
  flex: 1;
}

.day-split .day-list > * {
  flex: 1;
}

/* FB8-02: the KPI cards head the page in one row, then the calendar, the overdue
   work and the risks. */
.day-stats {
  grid-template-columns: repeat(3, 1fr);
  margin-bottom: var(--space-5);
}

/* Reports totals: same tile anatomy as My day, as many across as fit at a 200px
   floor — below that a seven-digit tonnage stops fitting beside its badge, and
   at 240px the fifth tile of Activity dropped to a row of its own.
   Flex instead of auto-fit tracks so the band always fills its width: with a
   track list, a tile count that does not divide evenly left the wrapped tile
   alone in a track and the row short by 500px. Now it stretches. */

.report-stats {
  display: flex;
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}

/* The 280px cap that keeps My day's three tiles from stretching is what left
   this band short of the column it sits in, so it is lifted here and the 200px
   floor is what drives the wrapping. */
.report-stats .stat-tile {
  flex: 1 1 200px;
  max-width: none;
  min-width: 0;
}

.report-stats .stat-icon {
  width: 42px;
  height: 42px;
}

/* KPI tile: tonal glyph on the left; figure + label beside it and the context
   line under those two. The tone (amber / navy / purple) lives in the glyph
   badge and the figure — the frame stays neutral on all four sides. */
.day-stats .stat-tile,
.day-stats .stat-tile[data-tone],
.report-stats .stat-tile {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "icon head go"
    "icon meta go";
  column-gap: var(--space-3);
  row-gap: 0;
  align-items: center;
  padding: var(--space-4) var(--space-5);
  border-left: 1px solid var(--border);
}

.stat-icon {
  grid-area: icon;
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--accent);
}

/* Figure and label share a baseline so they read as one headline. */
.stat-head {
  grid-area: head;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  min-width: 0;
}

.stat-tile[data-tone="warning"] .stat-icon {
  background: var(--status-progress-soft);
  color: var(--status-progress);
}

.stat-tile[data-tone="danger"] .stat-icon {
  background: var(--status-pending-soft);
  color: var(--status-pending);
}

.stat-tile[data-tone="risk"] .stat-icon {
  background: var(--risk-soft);
  color: var(--risk);
}

/* The tiles are links into the filtered list — the chevron says so on keyboard
   focus. It stays hidden on hover: the tiles do not react to the pointer. */
.stat-go {
  grid-area: go;
  color: var(--ink-muted);
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.stat-tile:focus-visible .stat-go {
  opacity: 1;
  transform: none;
}

.day-stats .stat-value {
  font-size: 32px;
}

/* Five tiles in a row: the label stacks under the figure instead of sitting
   beside it, and the frame is tighter than My day's three, so a seven-digit
   tonnage ("3,603,200") keeps its room beside the badge. */
.report-stats .stat-head {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.report-stats .stat-tile {
  padding: var(--space-4);
  container-type: inline-size;
}

/* Five tiles share one row, so the figure has to survive its longest reading:
   an all-years tonnage runs to eight digits ("16,192,969") and at a fixed 26px
   it overflowed the tile. The step is on the tile's own width, not the
   viewport's — the sidebar can take 180px off the row without the window
   changing at all. */
.report-stats .stat-value {
  font-size: clamp(20px, 11cqi, 26px);
}

.stat-meta {
  grid-area: meta;
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

/* Panels carry full-bleed .day-item rows (negative margin-inline). Without
   min-width:0 the grid item's auto minimum grows to that content and pushes the
   panel wider than its track, scrolling .content horizontally on narrow widths. */
.day-top > *,
.day-stats > * {
  min-width: 0;
}

.day-list {
  display: flex;
  flex-direction: column;
}

.day-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-subtle);
  text-decoration: none;
  color: var(--ink);
}

.day-item:last-child { border-bottom: none; }
.day-item:hover .day-item-title { color: var(--accent); }

.day-item-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.day-item-title {
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.day-item-rich { font-weight: 400; }
.day-item-rich strong { font-weight: 600; }

.day-item-meta {
  font-size: var(--text-xs);
  color: var(--ink-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.day-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-3);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

.day-empty svg { color: var(--status-done); opacity: 0.75; }

/* FB5-01: card header — a tone dot + title + count badge give each card an identity. */
.day-card-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.day-dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--status-na);
}

.day-dot[data-tone="overdue"] { background: var(--status-pending); }
.day-dot[data-tone="soon"] { background: var(--status-progress); }
.day-dot[data-tone="active"] { background: var(--accent); }
.day-dot[data-tone="risk"] { background: var(--risk); }

.day-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  color: var(--ink-soft);
  font-size: var(--text-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* FB5-01: agenda rows carry a leading urgency accent; hover is a full-width band
   that bleeds to the card edges (cancels the panel-body padding). */
[data-page="my-day"] .day-item {
  position: relative;
  margin-inline: calc(-1 * var(--space-5));
  padding-block: var(--space-3);
  padding-inline: var(--space-5);
  padding-left: calc(var(--space-5) + var(--space-3));
  transition: background var(--dur-fast) var(--ease);
}

[data-page="my-day"] .day-item::before {
  content: "";
  position: absolute;
  left: var(--space-5);
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 55%;
  border-radius: var(--radius-pill);
  background: var(--status-na);
}

[data-page="my-day"] .day-item[data-tone="overdue"]::before { background: var(--status-pending); }
[data-page="my-day"] .day-item[data-tone="soon"]::before { background: var(--status-progress); }
[data-page="my-day"] .day-item[data-tone="ok"]::before { background: var(--status-na); }

[data-page="my-day"] .day-item:hover {
  background: var(--row-hover);
}


/* FB4-03: active-risk rows link to the file; the meta line stays inside the risk tone. */
.day-risk { text-decoration: none; }
.day-risk:hover { filter: brightness(0.97); }
.day-risk .day-item-meta { color: inherit; opacity: 0.8; font-weight: 500; }

/* FB6-01: ETA notices card — each row carries the load action / loaded state on the right. */
.eta-item .day-item-main { text-decoration: none; color: inherit; }
.eta-item .btn.small { flex: none; }
.eta-loaded {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--status-done);
}

/* FB6-03: OneDrive quick-access menu in the My day header. */
.onedrive { position: relative; }
.onedrive > summary {
  list-style: none;
  cursor: pointer;
  gap: var(--space-2);
}
.onedrive > summary::-webkit-details-marker { display: none; }
.onedrive-menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: 20;
  width: 260px;
  padding: var(--space-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.onedrive-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--ink);
}
.onedrive-item:hover { background: var(--surface-sunken); }
.onedrive-item-icon { flex: none; color: var(--ink-soft); }
.onedrive-item-icon[data-kind="xls"] { color: var(--status-done); }
.onedrive-item-icon[data-kind="doc"] { color: var(--accent); }
.onedrive-item-text { display: flex; flex-direction: column; min-width: 0; }
.onedrive-item-text strong { font-size: var(--text-sm); font-weight: 600; }
.onedrive-item-text span { font-size: var(--text-xs); color: var(--ink-soft); }

/* Three KPI tiles side by side start cramping the figure + label + context line
   below ~1250px, so they stack from there. */
@media (max-width: 1250px) {
  .day-stats { grid-template-columns: 1fr; }
}


@media (max-width: 991px) {
  .day-top,
  .day-split { grid-template-columns: 1fr; }
}

@media (max-width: 767px) {
  .day-hero {
    margin: calc(-1 * var(--space-4)) calc(-1 * var(--space-4)) var(--space-4);
    padding: var(--space-5) var(--space-4) var(--space-4);
    min-height: 300px;
  }

  /* On phones the button drops into the flow, below the greeting subtitle. */
  .day-hero .tools {
    position: static;
    margin-top: var(--space-3);
  }

  /* Anchor the menu to the button's left edge so it doesn't run off-screen,
     and cap its width to the viewport. */
  .onedrive-menu {
    left: 0;
    right: auto;
    width: min(260px, calc(100vw - 2 * var(--space-4)));
  }
}


/* FB3-06: supervisor overview — the command bridge. Reuses the app's urgency
   semaphore (red overdue → amber soon → navy active → green closed) as the whole
   visual language, so the desk reads at a glance. Urgency fills are shared: */
[data-urgency="overdue"] { --urg: var(--status-pending); }
[data-urgency="soon"] { --urg: var(--status-progress); }
[data-urgency="active"] { --urg: var(--accent); }
[data-urgency="done"] { --urg: var(--status-done); }
[data-urgency="risk"] { --urg: var(--risk); }

/* Command banner — a contained navy console the supervisor lands on. Same
   palette, noise and glow recipe as the sidebar rail, with the radii and angle
   retuned for a wide, short box instead of a tall one. */
.command-banner {
  margin-bottom: var(--space-6);
  padding: var(--space-5) var(--space-6);
  border-radius: var(--radius-lg);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)' opacity='0.4'/%3E%3C/svg%3E"),
    radial-gradient(
      55% 150% at 100% 0%,
      hsl(202 92% 54% / 0.5) 0%,
      transparent 70%
    ),
    radial-gradient(
      50% 150% at 0% 96%,
      hsl(187 90% 48% / 0.26) 0%,
      transparent 72%
    ),
    linear-gradient(
      145deg,
      hsl(205 76% 31%) 0%,
      hsl(208 74% 24%) 48%,
      hsl(212 68% 18%) 100%
    );
  background-size: 140px 140px, 100% 100%, 100% 100%, 100% 100%;
  background-position: left top;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
  background-blend-mode: overlay, screen, screen, normal;
  color: #fff;
  box-shadow: var(--shadow);
}

.command-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.command-titles { display: flex; flex-direction: column; gap: 2px; }

.command-titles h1 {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #fff;
}

.command-sub {
  margin: 0;
  font-size: var(--text-sm);
  color: hsl(0 0% 100% / 0.72);
}

.command-date {
  display: inline-flex;
  align-items: center;
  padding: 6px var(--space-3);
  border-radius: var(--radius-pill);
  background: hsl(0 0% 100% / 0.1);
  border: 1px solid hsl(0 0% 100% / 0.22);
  font-size: var(--text-sm);
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
}

.command-status {
  margin: var(--space-4) 0 var(--space-5);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  font-size: var(--text-sm);
  color: hsl(0 0% 100% / 0.75);
}

.cmd-metric { display: inline-flex; align-items: baseline; gap: 6px; }
.cmd-metric b {
  font-size: var(--text-lg);
  font-weight: 700;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.cmd-metric[data-urgency] b { color: color-mix(in srgb, var(--urg) 55%, #fff); }

/* Fleet status bar — every operation distributed across the four urgency
   colours: the tower's radar sweep. Thin gaps keep each band distinct, even
   the navy one, against the dark console. */
.fleet-bar {
  display: flex;
  gap: 2px;
  height: 12px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: hsl(0 0% 100% / 0.08);
}

.fleet-seg { background: var(--urg); min-width: 3px; }

.fleet-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-3);
  font-size: var(--text-xs);
  color: hsl(0 0% 100% / 0.72);
}

.fleet-key { display: inline-flex; align-items: center; gap: 6px; }
.fleet-key b { color: #fff; font-variant-numeric: tabular-nums; }

.fleet-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--urg);
  flex: none;
}

/* Operator cards — one per operator, carrying a signal light for their worst
   open state. */
.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: var(--space-5);
  align-items: start;
}

.op-card {
  display: flex;
  flex-direction: column;
}

.op-card-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
}

.op-avatar {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: #fff;
  font-size: var(--text-sm);
  font-weight: 700;
}

.op-card-id { display: flex; flex-direction: column; min-width: 0; flex: 1; }

.op-card-name { font-size: var(--text-md); font-weight: 700; line-height: 1.2; }

.op-card-office { font-size: var(--text-xs); color: var(--ink-faint); }

.op-status {
  flex: none;
  align-self: flex-start;
  padding: 3px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--urg);
  background: color-mix(in srgb, var(--urg) 12%, transparent);
  white-space: nowrap;
}

.op-load { padding: 0 var(--space-5) var(--space-4); }

.op-load-bar {
  display: flex;
  gap: 2px;
  height: 8px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--surface-sunken, var(--border-subtle));
}

.op-load-seg { background: var(--urg); min-width: 4px; }
.op-load-seg.is-empty { flex: 1; background: var(--border-subtle); }

.op-load-keys {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-3);
  font-size: var(--text-xs);
  color: var(--ink-soft);
}

.op-key { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }

.op-card-body {
  padding: 0 var(--space-5);
  border-top: 1px solid var(--border-subtle);
}

.op-card-body .day-list { padding-top: var(--space-2); }

/* Deadline rows here are read-only — the card's "View operations" link is the
   single navigation, so drop the link hover affordance. */
.op-card .day-item { cursor: default; }
.op-card .day-item:hover .day-item-title { color: inherit; }

.op-card-foot {
  margin-top: auto;
  padding: var(--space-3) var(--space-5) var(--space-4);
}

@media (max-width: 767px) {
  .command-banner { padding: var(--space-5) var(--space-4); }
  .command-status { gap: var(--space-2) var(--space-4); }
  /* Hide the date pill on phones, like the My day hero. */
  .command-date { display: none; }
}

/* ---- AI clean-recap assistant (AI module) ---- */
.ai-cta {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--accent-soft);
  border-radius: var(--radius);
  background: linear-gradient(120deg, var(--accent-soft) 0%, transparent 70%);
}

.ai-cta-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
}

.ai-cta-text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.ai-cta-text strong { font-size: var(--text-base); }
.ai-cta-text span { font-size: var(--text-sm); color: var(--ink-soft); }

/* On phones the nowrap button can't share the row — stack the banner. */
@media (max-width: 767px) {
  .ai-cta {
    flex-direction: column;
    align-items: flex-start;
  }
  .ai-cta .btn {
    width: 100%;
  }
}

.ai-file-error { display: block; margin-top: var(--space-2); }

/* FB8-13: paste-the-email / upload-a-file switch inside the import modal. */
.recap-source {
  margin-bottom: var(--space-4);
}

.recap-paste {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: 1.5;
  resize: vertical;
}

/* Processing state */
.ai-processing {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-5);
  color: var(--ink-soft);
}

/* Two-column review: recap on the left, proposal on the right */
.ai-review-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}

/* Left column: the recap presented as the document the assistant read. */
.ai-recap {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
  position: sticky;
  top: 0;
}

.ai-recap-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  background: var(--surface-sunken);
}
.ai-recap-head .icon { color: var(--accent); flex: none; }
.ai-recap-title { display: block; font-size: var(--text-sm); font-weight: 700; color: var(--ink); }
.ai-recap-file { display: block; font-size: var(--text-xs); color: var(--ink-faint); }

.ai-recap-text {
  margin: 0;
  padding: var(--space-4);
  max-height: 56vh;
  overflow: auto;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.7;
  color: var(--ink-soft);
  white-space: pre-wrap;
}

/* Right column: the proposal, grouped */
.ai-group + .ai-group { margin-top: var(--space-6); }
.ai-group h3 {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}
.ai-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--border);
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 700;
}

.ai-group-hint {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

.ai-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: var(--space-3);
  border-left: 2px solid transparent;
  border-radius: var(--radius-sm);
}
.ai-item + .ai-item { border-top: 1px solid var(--border-subtle); }
.ai-item.is-active { background: var(--accent-soft); border-left-color: var(--accent); }
.ai-item[data-state="rejected"] { opacity: 0.55; }

.ai-item-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.ai-item-label {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-faint);
}
.ai-item-actions { flex: none; display: flex; gap: var(--space-1); }

.ai-item-value { font-size: var(--text-base); font-weight: 600; color: var(--ink); }

/* Deadline timing rule (relative windows / chained), not an absolute date */
.ai-item-when {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
}
.ai-item-when .icon { color: var(--accent); flex: none; }

.ai-item-value.is-rejected,
.ai-item-when.is-rejected,
.ai-item-clause.is-rejected { text-decoration: line-through; color: var(--ink-faint); }

/* Source clause, shown as a quiet citation from the recap */
.ai-item-clause {
  font-size: var(--text-xs);
  color: var(--ink-soft);
  font-style: italic;
  padding-left: var(--space-3);
  border-left: 2px solid var(--border-strong);
}

.ai-edit-input { width: 100%; margin-top: var(--space-2); }

.ai-tag {
  display: inline-block;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  vertical-align: middle;
}
.ai-tag-edited { background: var(--surface-sunken); color: var(--ink-faint); }

/* Sparkle in the review title */
.ai-spark { color: var(--accent); vertical-align: -3px; margin-right: 4px; }
.ai-btn-spark { vertical-align: -2px; margin-right: 4px; }

/* AI-16: the clause highlighted in the recap for the selected item */
.ai-clause {
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 3px;
  padding: 0 2px;
  box-shadow: 0 0 0 1px var(--accent);
}

/* Fields pre-filled by the assistant, until the user edits them */
.field.ai-filled .input,
.field.ai-filled .select {
  border-color: var(--accent);
  background: var(--accent-soft);
}

@media (max-width: 767px) {
  .ai-review-grid { grid-template-columns: 1fr; }
  .ai-recap { position: static; }
  .ai-recap-text { max-height: 30vh; }
}


/* Reports (RPT-01) — one report on screen at a time; the index is the sidebar */
.report > * + * {
  margin-top: var(--space-5);
}

/* Every report table scrolls inside its own box: the cross-tab is wide by
   definition and the page must never scroll sideways as a whole. */
.report .table-scroll {
  overflow-x: auto;
}


/* The rule runs the full width of the report, not the width of the tab labels:
   By office has two groups (rows and measure) and a border on each would read
   as a line broken in the middle. */
.report-groupby {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--border);
}

.report-groupby .tabs {
  min-width: 0;
  margin-bottom: 0;
  border-bottom: 0;
}

.report-dim {
  min-width: 0;
}

/* A setting with two mutually exclusive values, sitting next to a tab strip: it
   has to read as a control and not as another set of sections, so the chosen
   half is filled in the accent inside a sunken track, not underlined. Same
   pressed treatment as .chip-toggle.active, the system's other on/off control. */
.segmented {
  display: inline-flex;
  flex: none;
  gap: 2px;
  padding: 2px;
  margin-bottom: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

/* The inner radius is the outer one minus the track's padding, so the pressed
   half nests inside the border instead of leaving a sliver at each corner. */
.segment {
  padding: var(--space-1) var(--space-4);
  border: 1px solid transparent;
  border-radius: calc(var(--radius-sm) - 2px);
  background: none;
  color: var(--ink-faint);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.segment:hover {
  color: var(--ink);
}

.segment[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
}

/* The nowrap above is load-bearing here: column + wrap makes this a multi-line
   flex container, so the line's cross size becomes the widest tab strip's
   content width and .report-dim stretches past the panel instead of letting
   .tabs scroll. */
@media (max-width: 640px) {
  .report-groupby {
    flex-direction: column;
    align-items: stretch;
    border-bottom: 0;
  }

  /* Stacked, one rule across both groups would only underline the last one. */
  .report-groupby .tabs {
    border-bottom: 1px solid var(--border);
  }

  /* Stretched by the column's align-items, the pill would run the whole width
     with its two labels huddled on the left. */
  .segmented {
    align-self: flex-start;
  }
}

.report-table th.num,
.report-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Four short columns, so it doesn't need the 940px floor the dense lists use —
   that floor was scrolling the whole page sideways between ~1000 and ~1250px,
   which also cost the totals row a column. */
table.data.report-table {
  min-width: 0;
}

.report-table th.share-col,
.report-table td.share-col {
  width: 34%;
}

/* The detail tables page inside their panel, so the bar sits within the body's
   own padding: no edge-to-edge rule and no rounded bottom of its own — the
   table already closes on its totals row. */
.panel-body > .pagination {
  padding: var(--space-4) 0 0;
  border-top: none;
  border-radius: 0;
}

/* Bar and figure on one line: stacked, the share cell was setting the height of
   every row in the table. */
.share-cell {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.share-bar {
  flex: 1;
  min-width: 0;
  height: 8px;
  border-radius: 999px;
  background: var(--accent-soft);
  overflow: hidden;
}

.share-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
}

.share-pct {
  flex: none;
  width: 4ch;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  font-size: var(--text-sm);
}

@media (max-width: 991px) {
  .share-bar { display: none; }
  .share-pct { width: auto; }
}


/* One column per office plus the total and the share: below this the columns
   crush, so the cross-tab scrolls in its box instead. */
.report-crosstab {
  min-width: 760px;
}

/* A comparison table adds a totals row; it reads as the closing line of the
   table, not as another record. */
.report-table tfoot td {
  border-top: 1px solid var(--border);
  background: var(--surface-sunken);
  color: var(--ink);
  font-weight: 600;
}

/* Direction of a change — the only place a figure is coloured by whether it
   grew. Amber for a fall, never the semaphore's red: a drop is worth noticing,
   not an overdue deadline. */
.delta {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.delta[data-dir="up"] { color: var(--delta-up); }
.delta[data-dir="down"] { color: var(--delta-down); }

/* Inside a table the coloured figure competes with five other numbers in its
   row, so the change carries a tint: it is what makes the movement findable
   when scanning a column. Left as plain coloured text outside a table, where
   the figure is already the largest thing in its box. */
.report-table .delta {
  display: inline-block;
  padding: 1px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--status-na-soft);
}

.report-table .delta[data-dir="up"] { background: var(--delta-up-soft); }
.report-table .delta[data-dir="down"] { background: var(--delta-down-soft); }

/* Stacked, each row becomes a card, so the totals row has to be tinted as a
   card: on its cells the tint stops at the row's own side padding and the
   white gutters read as bands. */
@media (max-width: 991px) {
  .report-table tfoot tr {
    background: var(--surface-sunken);
    border-color: var(--border-strong);
  }

  .report-table tfoot td {
    background: transparent;
  }

  /* A cell that is empty on purpose (no share on the totals row) would stack as
     a column name with nothing after it. */
  table.data td:empty {
    display: none;
  }

  /* The share column's desktop width squeezes the stacked cell to a third of the
     card, which pulls its figure off the right edge every other row lines up on. */
  .report-table td.share-col {
    width: auto;
  }
}

/* Two comparison tables side by side where there is room for both — the
   counterparty file's main column is narrower than the reports page, so the
   pair stacks there instead of squeezing two tables into it. */
.report-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 460px), 1fr));
  gap: var(--space-5);
  align-items: start;
  margin-bottom: var(--space-5);
}

.report-pair > * {
  min-width: 0;
}

.panel + .report-pair {
  margin-top: var(--space-5);
}


/* C-11: port typeahead (js/combo.js). The panel is fixed and placed from JS, so
   a port field near the bottom of a modal is not clipped by it. */
.combo {
  position: relative;
  min-width: 0;
}

.combo > .input {
  width: 100%;
}

.combo-list {
  position: fixed;
  z-index: 60;
  max-height: 17rem;
  overflow-y: auto;
  padding: var(--space-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  box-shadow: var(--shadow-lg);
}

/* One row of the list: the port, and the ✕ for a port you added that nothing
   uses yet. */
.combo-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.combo-row > .combo-option {
  flex: 1;
  min-width: 0;
}

.combo-remove {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  padding: var(--space-1);
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
}

.combo-remove:hover {
  background: var(--surface-sunken);
  color: var(--status-pending);
}

.combo-option {
  display: block;
  width: 100%;
  padding: var(--space-2);
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--text-sm);
  text-align: left;
  cursor: pointer;
}

.combo-option:hover,
.combo-option.is-active {
  background: var(--surface-sunken);
}

/* Adding is the last row and reads as an action, not as one more port. */
.combo-add {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin-top: var(--space-1);
  border-top: 1px solid var(--border);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  padding-top: var(--space-2);
  color: var(--accent);
}

.combo-add-label {
  font-weight: 600;
}

.combo-add-value {
  color: var(--ink-soft);
}

/* ---- Forecast chart (FB22-02) ----
   Stacked columns in plain CSS: the flow by month, the same buckets the table
   under it prints. Marks stay thin and the grid stays out of the way — the
   figures are the subject, the geometry is only how they are compared. */

.chart {
  margin-bottom: var(--space-5);
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.chart-key {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* The swatch carries the identity so the label never has to wear the series
   colour — text stays in ink tokens. */
.chart-swatch {
  width: 10px;
  height: 10px;
  border-radius: 2px;
}

.chart-swatch[data-series="firm"],
.chart-bar[data-series="firm"] {
  background: var(--accent);
}

/* --delta-down, not the amber of the semaphore: with the table gone the plot has
   to carry its own contrast, and the lighter amber sat at 2.73:1 against the
   surface. This one clears 3:1 and keeps CVD separation from the blue. */
.chart-swatch[data-series="estimate"],
.chart-bar[data-series="estimate"] {
  background: var(--delta-down);
}

.chart {
  /* The band the bars are drawn in. 100 of --size is exactly this, and it is
     also what each column reserves, so the two cannot drift apart. */
  --chart-band: 160px;
}

.chart-plot {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
  /* No min-height: the columns reserve the band themselves, so the plot is the
     same height on every page of the nav. The padding is the room the label on
     the tallest month rides in, above the band. */
  padding-top: var(--space-5);
  overflow-x: auto;
  border-bottom: 1px solid var(--border);
}

/* Two rows: the band, then the tick. The band is reserved whether or not this
   page has anything tall in it, so paging no longer moves the panel underneath
   — and the stack still ends where its own data ends, which is what the tooltip
   and the peak label hang off. */
.chart-col {
  display: grid;
  grid-template-rows: var(--chart-band) auto;
  align-items: end;
  justify-items: center;
  flex: 1 1 0;
  gap: var(--space-2);
  min-width: 54px;
}

/* The stack grows from the baseline, so the segments are laid out bottom-up and
   the firm one sits under the estimate. */
/* Height comes from the bars, not from a fixed box — that is what lets the
   tooltip and the peak label sit on the top of the data instead of on the top
   of the plot. */
.chart-stack {
  position: relative;
  display: flex;
  flex-direction: column-reverse;
  width: 100%;
  max-width: 56px;
  gap: 2px;
}

/* --size is the bar's share of the tallest column, 0–100, set by the render.
   Here it becomes height; on a phone the same number becomes width. */
.chart-bar {
  height: calc(var(--size) * var(--chart-band) / 100);
  border-radius: 2px;
  min-height: 12px;
}

/* The months off the current page stay in the DOM so paging costs no render.
   The filler months at the end of the axis are only there to square the page
   off, so they are drawn — empty — on desktop and dropped on the phone. */
.chart-col[data-off] {
  display: none;
}

/* Only the top of the column is rounded — a data end, not a floating pill.
   4px is the mark spec, not a surface radius, so it is not one of the tokens.
   Which bar that is comes from the render, as data-top — see renderStackedChart. */
.chart-bar[data-top] {
  border-radius: 4px 4px 2px 2px;
}

/* Taken out of the flow: in the flow it ate the height of the very bar it
   labels, and the peak stopped reaching the top of the plot. Only the peak is
   labelled, and the peak always fills the stack, so the top of the stack is the
   top of its bar. */
.chart-value {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: var(--space-1);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* Every month carries its figure so the phone can print the lot; here only the
   tallest of the page is labelled and the rest are read off the hover. */
.chart-value:not([data-peak]) {
  display: none;
}

.chart-tick {
  font-size: var(--text-xs);
  color: var(--ink-faint);
  white-space: nowrap;
}

/* On a phone the plot turns on its side: a month per row, running down the
   screen to the last one with anything in it. Twelve columns across 360px is a
   sliver each and a sideways scroll to read the year — as rows every month gets
   the full width, its own figure, and no nav to operate. Same DOM, same one
   render: only the axis the bars are measured along changes. */
@media (max-width: 720px) {
  .chart-nav {
    display: none;
  }

  .chart-plot {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
    min-height: 0;
    padding-top: 0;
    overflow-x: visible;
    border-bottom: 0;
  }

  /* The page the nav left behind is meaningless here — the whole horizon is on
     screen — so the off-page months come back and only the filler drops out. */
  .chart-col[data-off] {
    display: flex;
  }

  .chart-col[data-tail] {
    display: none;
  }

  /* Relative, and the stack static under it, so the figure anchors to the end of
     the row rather than to the end of the bars — a ragged column of numbers is
     unreadable next to a bar chart. The padding is the room it sits in. */
  .chart-col {
    position: relative;
    display: flex;
    flex: 0 0 auto;
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
    padding-right: 6em;
  }

  /* The month reads first, before the bar it labels. */
  .chart-tick {
    order: -1;
    flex: 0 0 5.5em;
  }

  .chart-stack {
    position: static;
    flex: 1 1 auto;
    flex-direction: row;
    max-width: none;
    height: 14px;
  }

  .chart-bar {
    width: calc(var(--size) * 1%);
    height: auto;
    min-width: 2px;
  }

  /* Turned with the bars: the data end is now the right-hand tip of the row. */
  .chart-bar[data-top] {
    border-radius: 2px 4px 4px 2px;
  }

  /* Out of the corner it occupies on desktop and onto the end of its own row,
     where there is no hover to reveal it. */
  .chart-value {
    top: 50%;
    right: 0;
    bottom: auto;
    left: auto;
    margin-bottom: 0;
    transform: translateY(-50%);
  }

  .chart-value:not([data-peak]) {
    display: block;
  }
}

/* FB22-01: the consequences of a terminal action, listed inside its modal — what
   stops, what leaves the money reports and what stays in the statistics. Its own
   component because the wording is the point: cancelling reads as destructive and
   the list is what makes it accurate. */
.modal-notice {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  list-style: none;
  background: var(--surface-sunken);
  border-radius: var(--radius);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.modal-notice li {
  position: relative;
  padding-left: var(--space-4);
}

.modal-notice li + li {
  margin-top: var(--space-2);
}

.modal-notice li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--status-na);
}

/* FB22-01: why a cancelled file was cancelled, under its title. Grey rather than
   red — it is settled, not an alert to act on. */
.file-cancelled {
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--status-pending-tint);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--status-pending);
}

.file-cancelled strong {
  color: var(--status-pending);
  font-weight: 700;
}

/* Who cancelled it and when, on the same line as the reason: the banner is one
   sentence, and breaking it in two made it a paragraph. */
.file-cancelled .cancelled-by {
  color: var(--status-pending);
  opacity: 0.75;
}


/* Picking which document a new version belongs to: the radio leads the row like
   every other single-choice list here, and the name carries its current version
   and last upload underneath — without them two rows of the same type are
   indistinguishable, which is the whole reason the list is shown. */
.dup-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-3);
}

.dup-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.dup-item:hover {
  background: var(--surface-sunken);
}

.dup-item-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.dup-item-name {
  overflow-wrap: anywhere;
}

.dup-item-meta {
  color: var(--ink-faint);
  font-size: var(--text-sm);
}

/* Two links in a panel head: they sit together on the right and wrap as a pair
   when the panel is too narrow to hold the title beside them. */
.panel-head-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* Long free text (the comment a file was opened with) inside a data panel:
   two lines by default, the rest behind Show more. */
.summary-item.summary-block {
  display: block;
}

.summary-item.summary-block .k {
  display: block;
  width: auto;
  margin-bottom: var(--space-1);
}

.summary-item.summary-block .v {
  font-weight: 500;
}

.clamp-text {
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.clamp.is-open .clamp-text {
  -webkit-line-clamp: unset;
  line-clamp: unset;
}

.clamp-toggle {
  margin-top: 2px;
}
