.req_sheet {
  border: 1px solid #d8d8d8;
  border-radius: 6px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
  max-width: 900px;
  margin: 0 auto 2rem;
  padding: 2rem 2.5rem;
  font-family: "Georgia", "Times New Roman", serif;
  color: #2b2b2b;

  /* ---- Letterhead ---- */
  .card-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 3px double #333;
    padding-bottom: 1rem;
    margin-bottom: 1.5rem;
  }

  .letterhead-left {
    display: flex;
    align-items: center;
    gap: 0.75rem;
  }

  .logo {
    height: 42px;
    width: auto;
  }

  .org-name {
    font-size: 1.15rem;
    font-weight: bold;
    letter-spacing: 0.02em;
  }

  .org-sub {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #777;
  }

  .letterhead-right {
    text-align: right;
  }

  .id {
    font-family: "Courier New", monospace;
    font-size: 1.1rem;
    font-weight: bold;
    /* color: #444; */
  }

  /* ---- Status badge ---- */
  .status-badge {
    display: inline-block;
    margin-top: 0.25rem;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: #eee;
    color: #555;

    &.status-approved  { background: #d8f3dc; color: #1b6b35; }
    /* Signed off by the supervisor, still waiting on management — the approved green,
       lightened, so the pair read as steps of one thing rather than two states. */
    &.status-pre_approved { background: #eaf6d9; color: #4a6b1b; }
    /* An expense report the treasurer has sent to the parent company to be paid. */
    &.status-processed  { background: #e6ddf7; color: #4b2e83; }
    &.status-denied     { background: #fbd7d7; color: #9c1c1c; }
    &.status-pending    { background: #fff3cd; color: #8a6500; }
    &.status-draft      { background: #e2e3e5; color: #41464b; }
    &.status-ordered    { background: #d3e3fc; color: #1a4f9c; }
    &.status-cancelled  { background: #f1f1f1; color: #888; text-decoration: line-through; }
  }

  /* ---- Field grid ---- */
  .section {
    margin-bottom: 1.25rem;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 1rem 2rem;
  }

  .section-title {
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #555;
    margin-bottom: 0.75rem;
  }

  .field {
    display: flex;
    flex-direction: column;
  }

  .label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #999;
    margin-bottom: 0.15rem;
  }

  .value {
    font-size: 0.98rem;
  }

  /* A part timer's leave, day by day (requests/_request.html.erb) */
  .day-hours-block {
    margin-bottom: 1.25rem;
  }

  .day-hours {
    list-style: none;
    padding: 0;
    margin: 0 0 0.75rem;
    font-size: 0.98rem;

    li {
      padding: 0.1rem 0;
    }
  }

  .comment {
    margin-top: 0.5rem;
  }

  hr {
    border: none;
    border-top: 1px solid #ddd;
    margin: 1.5rem 0;
  }

  /* ---- Line items table ---- */
  .line-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;

    th {
      text-align: left;
      font-size: 0.72rem;
      text-transform: uppercase;
      letter-spacing: 0.05em;
      color: #999;
      border-bottom: 2px solid #333;
      padding: 0.4rem 0.5rem;
    }

    td {
      padding: 0.6rem 0.5rem;
      border-bottom: 1px solid #eee;
      vertical-align: top;
    }
  }

  .num {
    text-align: right;
  }

  .total-cell {
    font-weight: 600;
  }

  .grand-total-label {
    font-weight: 600;
    color: #555;
    padding-top: 0.75rem;
  }

  .grand-total-value {
    font-weight: bold;
    font-size: 1.05rem;
    padding-top: 0.75rem;
    border-top: 2px solid #333;
  }

  .alt-link {
    font-size: 0.82rem;
    color: #777;
  }

  /* Tax/shipping/tariffs: no quantity, no unit cost, just the charge and the amount. */
  .misc-line td {
    color: #555;
    font-style: italic;
  }
}

/* ---- Line items on the purchase form ---- */
.purchase-lines {
  .lines-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin: 1.25rem 0 0.5rem;
  }

  .line-row {
    border: 1px solid #ddd;
    border-radius: 6px;
    padding: 0.75rem 0.75rem 0.25rem;
    margin-bottom: 0.75rem;
    background: rgba(0, 0, 0, 0.015);
  }

  .line-row-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.5rem;
  }

  .line-row-title {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #999;
  }

  /* Alternate links: a stack of inputs, each with its own remove button beside it. */
  .link-list-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.25rem;
  }

  .link-add {
    font-size: 0.78rem;
    text-decoration: none;
  }

  .link-row {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-bottom: 0.35rem;

    /* The extra links stack under the first one and read as one list, so the gap above the
       first of them matches the gap between any two. On the first-child rather than the
       container, which is empty until + is pressed and shouldn't leave a hole. */
    &:first-child {
      margin-top: 0.35rem;
    }

    input {
      flex: 1 1 auto;
      min-width: 0;
    }

    .link-remove {
      flex: 0 0 auto;
      line-height: 1;
    }
  }

  .line-row-total,
  .lines-total {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 0.5rem;
    padding-bottom: 0.5rem;
  }

  .lines-total {
    padding-top: 0.6rem;
    margin-top: 0.5rem;
  }

  /* Each section's own tally: a hairline rule, and the same weight as a line total. It reads
     as the end of the list above it rather than competing with the grand total below. */
  .lines-subtotal {
    border-top: 1px solid #ddd;

    .value {
      font-weight: 600;
    }
  }

  .lines-grand-total {
    border-top: 2px solid #333;

    .value {
      font-size: 1.15rem;
      font-weight: bold;
    }
  }

  /* The "a link or an attachment" stand-in (see _purchase_lines.html.erb). Kept rendered
     rather than display:none — a control that isn't rendered is exempt from validation,
     which is the one thing this element exists to take part in. */
  .link-proof,
  .link-proof-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
    opacity: 0;
    pointer-events: none;
  }
}

/* The "a link on an item, or an attachment" rule is answered by two fields in two places, so
   both say the same sentence. The Attachments side sits outside .purchase-lines, hence the
   top-level rule. */
.link-proof-hint {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.95rem;
  font-weight: 500;
}

/* ---- Versions timeline ---- */
.main-timeline {
  position: relative;
  padding: 1rem 0;
}

.main-timeline::after {
  content: '';
  position: absolute;
  width: 4px;
  background: #d8d8d8;
  top: 0;
  bottom: 0;
  left: 50%;
  margin-left: -2px;
  border-radius: 2px;
}

.timeline {
  position: relative;
  width: 50%;
  padding-bottom: 1.5rem;
}

.timeline.left {
  padding-right: 2.5rem;
  left: 0;
}

.timeline.right {
  padding-left: 2.5rem;
  left: 50%;
}

/* Dot on the center line */
.timeline::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 16px;
  background: #939597;
  border: 3px solid #fff;
  top: 1rem;
  border-radius: 50%;
  z-index: 1;
  box-shadow: 0 0 0 2px #d8d8d8;
}

.timeline.left::after {
  right: -10px;
}

.timeline.right::after {
  left: -10px;
}

/* Arrow pointers */
.timeline.left::before {
  content: '';
  position: absolute;
  top: 1.15rem;
  z-index: 1;
  right: 14px;
  border: 6px solid transparent;
  border-left-color: #fff;
}

.timeline.right::before {
  content: '';
  position: absolute;
  top: 1.15rem;
  z-index: 1;
  left: 14px;
  border: 6px solid transparent;
  border-right-color: #fff;
}

/* Cards inside timeline */
.timeline .card {
  border: 1px solid #e8e8e8;
  border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  background: #fff;
  margin: 0;
}

.timeline .card .card-body {
  padding: 1rem 1.25rem;
}

.timeline-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}

.timeline-date {
  font-family: "Courier New", monospace;
  font-size: 0.82rem;
  color: #777;
  white-space: nowrap;
}

.timeline-user {
  font-size: 0.85rem;
  font-weight: 600;
  color: #555;
  margin-bottom: 0.5rem;
}

/* The lines a "Create" entry swallowed — what the request was filed with. */
.timeline-lines {
  font-size: 0.8rem;
  margin-bottom: 0.5rem;

  .label {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #999;
  }

  ul {
    margin: 0.15rem 0 0;
    padding-left: 1.1rem;
  }

  li {
    color: #555;
  }
}

/* Which line an item entry is about — "Update" on its own doesn't say. */
.timeline-subject {
  font-size: 0.85rem;
  color: #333;
  margin-bottom: 0.5rem;
  font-style: italic;
}

/* The approver's box and its three buttons. Sits with the page actions rather than in
   the timeline: it is where a decision is made, not where one is read back. */
.decision-form {
  max-width: 480px;
  margin: 0.5rem 0 1rem;

  .form-label {
    font-size: 0.85rem;
    color: #555;
  }
}

.decision-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* What somebody said — either a comment entry of its own, or the words that came with a
   decision, folded into it (TimelineHelper#absorbs_comment?). Same markup either way,
   because it is the same thing. */
.timeline-comment {
  font-size: 0.9rem;
  color: #333;
  margin-bottom: 0.5rem;
  white-space: pre-wrap;

  p {
    margin-bottom: 0.4rem;
  }

  p:last-child {
    margin-bottom: 0;
  }
}

/* The box for adding to the thread, above the timeline on the request page. Held to the
   sheet's full content width so it lines up with the timeline below it and the page reads
   as one column. The explicit width matters: .req_sheet is a Bootstrap .card, so this is a
   column-flex item, and auto cross-axis margins would otherwise beat the default stretch
   and shrink the box to the textarea's intrinsic width. */
.comment-form {
  width: 100%;
  max-width: 900px;
  margin: 1.5rem auto 0;
}

/* Event badges */
.version-event {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;

  &.version-event-create  { background: #d8f3dc; color: #1b6b35; }
  &.version-event-update  { background: #fff3cd; color: #8a6500; }
  &.version-event-destroy { background: #fbd7d7; color: #9c1c1c; }
}

/* Changes sub-table inside cards */
.changes-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.78rem;
  margin-top: 0.25rem;

  th {
    text-align: left;
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #999;
    border-bottom: 1px solid #ddd;
    padding: 0.2rem 0.35rem;
  }

  td {
    padding: 0.2rem 0.35rem;
    border-bottom: 1px solid #f0f0f0;
  }

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

.change-field {
  font-weight: 600;
  color: #555;
  white-space: nowrap;
}

.change-old {
  color: #9c1c1c;
  text-decoration: line-through;
}

.change-new {
  color: #1b6b35;
}

/* Responsive: single column on narrow screens */
@media screen and (max-width: 768px) {
  .main-timeline::after {
    left: 20px;
  }

  .timeline {
    width: 100%;
    padding-left: 50px;
    padding-right: 1rem;
  }

  .timeline.left,
  .timeline.right {
    left: 0;
    padding-left: 50px;
    padding-right: 1rem;
  }

  .timeline.left::after,
  .timeline.right::after {
    left: 12px;
  }

  .timeline.left::before,
  .timeline.right::before {
    left: 34px;
    right: auto;
    border: 6px solid transparent;
    border-right-color: #fff;
    border-left-color: transparent;
  }
}

/* ---- Attachment viewer modal ---- */
.attachment-list {
  margin-bottom: 0;
}

/* The dialog covers the page; stop the document scrolling behind it on touch. */
body.attachment-viewer-open {
  overflow: hidden;
}

dialog.attachment-viewer {
  /* As large as the screen allows, less a sliver so it still reads as a modal. */
  width: 96vw;
  height: 94vh;
  height: 94dvh;
  max-width: 96vw;
  max-height: 94vh;
  max-height: 94dvh;
  display: none;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--bs-border-color, #d8d8d8);
  border-radius: 6px;
  background: var(--bs-body-bg, #fff);
  color: var(--bs-body-color, #2b2b2b);
  /* The request sheet is set in Georgia; the viewer is chrome, not letterhead. */
  font-family: var(--bs-body-font-family, system-ui, sans-serif);
}

dialog.attachment-viewer[open] {
  display: flex;
  flex-direction: column;
}

dialog.attachment-viewer::backdrop {
  background: rgba(0, 0, 0, 0.6);
}

.attachment-viewer-bar {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--bs-border-color, #d8d8d8);
}

.attachment-viewer-name {
  /* min-width lets a long filename actually shrink and ellipsize; a flex item
     won't go below its content width without it. */
  min-width: 0;
  overflow: hidden;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.attachment-viewer-buttons {
  display: flex;
  flex: 0 0 auto;
  gap: 0.5rem;
}

/* Contents are centred with auto margins rather than justify-content: when
   they outgrow the modal the margins collapse to 0, so the top stays reachable
   instead of being scrolled off. */
.attachment-viewer-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  overflow: auto;
  /* Reserve the scrollbar so a multi-page PDF doesn't reflow its page widths. */
  scrollbar-gutter: stable;
  padding: 0.75rem;
  text-align: center;
  background: var(--bs-tertiary-bg, #f1f1f1);
  -webkit-overflow-scrolling: touch;
}

/* Never upscale — a small receipt blown up to fill the modal is just blurry. */
.attachment-viewer-image {
  max-width: 100%;
  max-height: 100%;
  margin: auto;
  object-fit: contain;
  background: #fff;
}

/* The browser's own viewer fills the modal and handles its own zoom and scroll. */
.attachment-viewer-frame {
  flex: 1 1 auto;
  width: 100%;
  border: 0;
  background: #fff;
}

.attachment-viewer-pages {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  margin: auto;
}

/* Hidden by the controller when empty — an empty flex child with auto margins
   would still claim a share of the free space and push the preview off centre. */
.attachment-viewer-notice {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  margin: auto;
}

/* Sized by the controller to fit the modal; the canvas fills it once drawn. */
.attachment-viewer-page {
  flex: 0 0 auto;
  background: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}

.attachment-viewer-page canvas {
  display: block;
}

.attachment-viewer-status {
  margin: auto;
  padding: 1rem;
  color: var(--bs-secondary-color, #777);
}

/* Phones get the whole screen; a margin there is wasted reading room. */
@media (max-width: 576px) {
  dialog.attachment-viewer {
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    max-width: 100vw;
    max-height: 100vh;
    max-height: 100dvh;
    border: 0;
    border-radius: 0;
  }
}

@media print {
  .page-header, .navbar,
  .req_header,
  .breadcrumb,
  .main-timeline,
  dialog.attachment-viewer {
    display: none !important;
  }

  .req_sheet.card {
    box-shadow: none;
    border: none;
    padding: 0;
  }
}
/* ---- Expense report sheet ----------------------------------------------
   A screen copy of the ministry's Employee Expense Report spreadsheet: the
   same header block, the same fixed 1..31 grid, the same totals and
   signature rows. ExpenseWorkbook exports the identical sheet as .xlsx by
   filling the real workbook, so the two are meant to match — change one and
   check the other. Deliberately dense and monochrome; it's a form, not a
   dashboard. */
.expense-sheet {
  /* Every colour in the sheet is one of these three, so the dark theme has one place to
     flip them (see the dark-mode block at the foot of this file) instead of restating each
     rule. The ink and the rules are the same near-black on paper, but they part company on
     a dark background — text goes fully white, the hairlines stay a wash. */
  --expense-ink: #111;
  --expense-rule: #111;
  --expense-band: #d9d9d9;

  font-size: 0.72rem;
  color: var(--expense-ink);
}

/* The sheet needs more room than the letterhead card gives the other request
   kinds, and it's the whole content of the page when it's there. */
.req_sheet:has(.expense-sheet) {
  max-width: 1150px;
}

.expense-sheet-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 0.5rem;
}

.expense-sheet-title {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-weight: bold;
  font-size: 0.9rem;
}

.expense-sheet-title .logo {
  height: 42px;
}

.expense-sheet-title-main {
  font-size: 1rem;
}

.expense-sheet-fields {
  border-collapse: collapse;
}

.expense-sheet-fields th {
  font-weight: normal;
  text-align: right;
  padding: 0.15rem 0.5rem;
  white-space: nowrap;
}

.expense-sheet-fields td {
  border-bottom: 1px solid var(--expense-rule);
  min-width: 9rem;
  padding: 0.15rem 0.5rem;
  font-weight: bold;
  text-align: center;
}

/* Thirteen columns of the paper form, so the card it sits in is widened to suit
   (see .req_sheet:has(.expense-sheet)) and the grid itself is laid out to fixed
   proportions — the colgroup in _expense_sheet.html.erb — rather than letting a
   long heading like "Fully Entertained" claim a column of its own width. */
.expense-grid {
  border-collapse: collapse;
  width: 100%;
  table-layout: fixed;
  min-width: 58rem;
}

.expense-grid th,
.expense-grid td {
  border: 1px solid var(--expense-rule);
  padding: 0.1rem 0.25rem;
  vertical-align: middle;
}

.expense-grid thead th {
  text-align: center;
  font-size: 0.62rem;
  font-weight: bold;
  line-height: 1.15;
  white-space: normal;
}

.expense-grid tbody td {
  height: 1.35rem;
}

.expense-grid td.day,
.expense-grid th.per-diem-head {
  text-align: center;
}

.expense-grid .num {
  text-align: right;
  white-space: nowrap;
}

.expense-grid tfoot th {
  border: none;
  text-align: right;
  padding-right: 0.5rem;
  white-space: nowrap;
}

.expense-grid .receipts-note {
  background: var(--expense-band);
  text-align: center;
  font-weight: bold;
  font-size: 0.8rem;
  letter-spacing: 0.03em;
}

.expense-grid tfoot .totals td {
  font-weight: bold;
}

.expense-grid tfoot .totals .grand {
  font-size: 0.8rem;
}

.expense-grid .reimbursement-label {
  border: none;
  font-weight: bold;
  font-size: 0.65rem;
  white-space: nowrap;
}

.expense-sheet-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  align-items: flex-end;
  margin-top: 0.75rem;
}

.office-use {
  flex: 1 1 20rem;
}

.office-use-label,
.approved-by {
  text-align: center;
  font-weight: bold;
  border: 1px solid var(--expense-rule);
  padding: 0.1rem;
}

.office-use-box {
  border: 1px solid var(--expense-rule);
  border-top: none;
  height: 5rem;
}

.approvals {
  flex: 0 1 16rem;
}

.signature-boxes {
  display: flex;
}

.signature-boxes > div {
  flex: 1;
  border: 1px solid var(--expense-rule);
  border-top: none;
  height: 4rem;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
}

.signature-boxes > div + div {
  border-left: none;
}

.sig-label {
  font-weight: bold;
  font-size: 0.62rem;
}

.employee-signature {
  flex: 1 1 14rem;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.employee-signature .sig-line {
  display: block;
  width: 100%;
  border-bottom: 1px solid var(--expense-rule);
  height: 3.5rem;
}


/* ---- Dark mode ----
   The request sheet is drawn as a letterhead, and every colour in it was picked against white
   paper: mid-greys for the labels and rules, pale tints behind the status pills, white cards
   down the timeline. Bootstrap's dark theme flips the page and the text that merely inherits,
   which leaves exactly the colours this file states outright — so those are what this block
   restates. Scoped to .req_sheet, .main-timeline and .expense-sheet: the first two are the
   whole show page and nothing else, and the sheet is scoped on its own because it is the one
   piece of this that the form renders too, in the Preview frame.

   Text goes white throughout. The pills and the before/after diff keep their meaning without
   it: the pills carry a translucent wash of their old colour behind the white, and a removed
   value is still struck through. */
[data-bs-theme="dark"] {
  /* Surfaces the light theme painted white. Both the timeline card and the little arrow that
     points at it read from this, so they can't drift out of step. */
  --req-sheet-card-bg: var(--bs-tertiary-bg, #2b3035);
  /* Rules and hairlines. The sheet leans on borders to separate things, and at #333 on a dark
     background they simply aren't there. */
  --req-sheet-rule: rgba(255, 255, 255, 0.55);
  --req-sheet-hairline: rgba(255, 255, 255, 0.15);

  /* The expense sheet is a copy of a printed form, so it states its own near-black ink and
     rules rather than inheriting them — which is why the .req_sheet rule below can't reach
     it, and why it carries its own set of variables to flip. The grid is nothing but its
     borders, so they get the full rule weight rather than the hairline. The "attach your
     receipts" band goes the way the status pills do: a translucent white wash, white text. */
  .expense-sheet {
    --expense-ink: #fff;
    --expense-rule: var(--req-sheet-rule);
    --expense-band: rgba(255, 255, 255, 0.14);
  }

  .req_sheet,
  .main-timeline {
    color: #fff;
    /* The product links go white with everything else — they keep their underline, which is
       what marks them as links here, and it puts them in step with .alt-link beside them.
       Set through Bootstrap's own variable so :hover and :focus follow rather than needing
       their own rules. */
    --bs-link-color-rgb: 255, 255, 255;
    --bs-link-hover-color-rgb: 255, 255, 255;
  }

  .req_sheet {
    border-color: var(--bs-border-color, #495057);

    .card-title { border-bottom-color: var(--req-sheet-rule); }

    .org-sub,
    .section-title,
    .label,
    .grand-total-label,
    .alt-link {
      color: #fff;
    }

    hr { border-top-color: var(--req-sheet-hairline); }

    .line-table {
      th {
        color: #fff;
        border-bottom-color: var(--req-sheet-rule);
      }

      td { border-bottom-color: var(--req-sheet-hairline); }
    }

    .grand-total-value { border-top-color: var(--req-sheet-rule); }

    /* Tax, shipping and the like: italic is what sets them apart, not the grey. */
    .misc-line td { color: #fff; }
  }

  /* Status pills and timeline event badges. The wash behind the white still says which one
     it is; at 0.35 alpha over the dark page each stays distinguishable from the others. */
  .req_sheet .status-badge,
  .version-event {
    color: #fff;
    background: rgba(255, 255, 255, 0.14);
  }

  .req_sheet .status-badge {
    &.status-approved  { background: rgba(25, 135, 84, 0.45); }
    &.status-pre_approved { background: rgba(25, 135, 84, 0.24); }
    &.status-processed { background: rgba(111, 66, 193, 0.5); }
    &.status-denied    { background: rgba(220, 53, 69, 0.45); }
    &.status-pending   { background: rgba(255, 193, 7, 0.35); }
    &.status-draft     { background: rgba(255, 255, 255, 0.16); }
    &.status-ordered   { background: rgba(13, 110, 253, 0.45); }
    &.status-cancelled { background: rgba(255, 255, 255, 0.1); }
  }

  .version-event {
    &.version-event-create  { background: rgba(25, 135, 84, 0.45); }
    &.version-event-update  { background: rgba(255, 193, 7, 0.35); }
    &.version-event-destroy { background: rgba(220, 53, 69, 0.45); }
  }

  /* ---- Timeline ---- */
  .main-timeline::after { background: var(--req-sheet-hairline); }

  .timeline::after {
    background: var(--bs-secondary-color, #939597);
    /* The dot sits on the spine and was ringed in white to punch a hole in it; the hole has
       to be the page colour, whatever that is. */
    border-color: var(--bs-body-bg, #212529);
    box-shadow: 0 0 0 2px var(--req-sheet-hairline);
  }

  .timeline.left::before { border-left-color: var(--req-sheet-card-bg); }
  .timeline.right::before { border-right-color: var(--req-sheet-card-bg); }

  .timeline .card {
    background: var(--req-sheet-card-bg);
    border-color: var(--bs-border-color, #495057);
  }

  .timeline-date,
  .timeline-user,
  .timeline-subject,
  .timeline-lines .label,
  .timeline-lines li,
  .change-field,
  .change-old,
  .change-new {
    color: #fff;
  }

  .changes-table {
    th {
      color: #fff;
      border-bottom-color: var(--req-sheet-hairline);
    }

    td { border-bottom-color: var(--req-sheet-hairline); }
  }
}

/* On narrow screens every card's arrow points the same way (see the light-theme rule above),
   so the dark surface has to follow it over to that side too. */
@media screen and (max-width: 768px) {
  [data-bs-theme="dark"] .timeline.left::before,
  [data-bs-theme="dark"] .timeline.right::before {
    border-right-color: var(--req-sheet-card-bg);
    border-left-color: transparent;
  }
}


/* ---- Request page header ----------------------------------------------
   The header is its own column above the sheet, at the sheet's width and centred on it:
   title, then a toolbar of the one-click actions, then the callout that says what the
   request is waiting for and offers only that. Nothing in it is an open form field —
   see reveal_controller. */

/* The title and the buttons beside it, starting at the sheet's own left edge. */
.req_header-title {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.req_header-meta {
  margin-left: 0.5rem;
  font-size: 0.9rem;
  font-weight: normal;
  color: var(--bs-secondary-color, #777);
}

/* The buttons and the fields they open share the heading row, so they have to stop
   inheriting its type — a textarea set in h1 bold is not a textarea anybody wants. */
.req_header .decision-form {
  margin: 0;
  font-size: 1rem;
  font-weight: 400;
}

/* An opened field takes the whole width and drops below the title rather than living as a
   sliver between two buttons. reveal_controller marks the form it opened. */
.req_header .decision-form.is-open {
  flex: 1 1 100%;
}

/* Where the buttons go when the title is turned off and there is no heading row to sit in.
   Marked off by rules rather than boxed. */
.req-toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding: 0.5rem 0;
  margin-bottom: 1rem;
  border-top: 1px solid var(--bs-border-color, #dee2e6);
  border-bottom: 1px solid var(--bs-border-color, #dee2e6);
}

.req-toolbar:empty {
  display: none;
}

.req-toolbar .decision-form {
  margin: 0;
}

/* Held to .req_sheet's width and lined up with it, so the header's left edge is the
   sheet's left edge rather than the window's. */
.req-header-column {
  max-width: 900px;
  margin: 0 auto;
}

/* The actions inside the callout: one form per side, its buttons on a row and their
   fields opening beneath them (reveal_controller). */
.req-action-line {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: flex-start;
}

.req-action-line .decision-form {
  margin: 0;
  max-width: none;
}

/* An armed action takes the whole width, so its fields are not a sliver beside somebody
   else's buttons — reveal_controller marks the form it armed. */
.req-action-line > .decision-form.is-open {
  flex: 1 1 100%;
}

/* The one submitter, under the fields it sends. Only on show while something is armed —
   there is nothing to submit until an action has been chosen. */
.decision-submit {
  margin-top: 0.75rem;
}

/* What Submit will do. Sits under the button row rather than in a tooltip: the two
   actions it tells apart look alike on purpose, and a difference you have to hover to find
   is not a difference the reader will notice. */
.req-hint {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
  color: var(--bs-secondary-color, #666);
}

/* The callout above the request that carries whatever is left to do. */
.req-banner {
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-left-width: 4px;
  border-radius: 0;
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
}

.req-banner-waiting {
  border-left-color: #ba7517;
  background: rgba(186, 117, 23, 0.08);
}

/* Your part is done and somebody else has it — still open, so not green. */
.req-banner-them {
  border-left-color: #378add;
  background: rgba(55, 138, 221, 0.08);
}

/* Nobody owes anything. The actions are still there; the nagging is not. */
.req-banner-done {
  border-left-color: #639922;
  background: rgba(99, 153, 34, 0.08);
}

.req-banner-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.req-banner-body {
  margin: 0.25rem 0 0.5rem;
  font-size: 0.9rem;
  color: var(--bs-secondary-color, #666);
}

.req-banner .decision-form {
  margin: 0.5rem 0 0;
}
