/* Gray Hawk T&E — brand: Orange #FF7300, Gray #595959, Calibri-family */
:root {
  --orange:#FF7300; --gray:#595959; --light:#F5F5F5; --dark:#333;
  /* Sticky-chrome offsets — see the "Pinned chrome" section near the end of
     this file. These defaults are the MEASURED desktop values (header = 60px
     at 1280px wide) so the feature still works with JavaScript disabled;
     base.html overwrites both with the live measurement. */
  --navh:60px; --stickytop:60px;
}
* { box-sizing:border-box; }
body { margin:0; font-family:Calibri,'Segoe UI',Arial,sans-serif; color:var(--dark); background:#fff; }
/* The nav header pins to the top of the window (Bucket B #6). `background` is
   not decoration here: the computed background was rgba(0,0,0,0) before this
   change — it only LOOKED white because <body> is white behind it — and a
   pinned transparent header has the page's data rows scrolling through it. */
header { display:flex; align-items:center; gap:12px; padding:8px 16px; border-bottom:3px solid var(--orange); flex-wrap:wrap;
         position:sticky; top:0; z-index:60; background:#fff; }
.wordmark { font-weight:bold; letter-spacing:2px; font-size:1.15rem; }
.wordmark .gh { color:var(--orange); } .wordmark .ls { color:var(--gray); font-size:.8rem; letter-spacing:3px; display:block; }
.eyebrow { font-size:.7rem; letter-spacing:2px; color:var(--gray); }
nav { margin-left:auto; display:flex; gap:10px; align-items:center; }
nav a { color:var(--gray); text-decoration:none; padding:6px 10px; border-radius:6px; }
nav a.active, nav a:hover { background:var(--light); color:var(--orange); }
main { max-width:1160px; margin:0 auto; padding:16px; }
/* Content links inside the page body (not nav, not buttons): brand orange.
   .link is the standard inline-link class used across the app; bare <a> in
   page content inherits the same treatment. Buttons (.btn/.secondary) and
   already-styled link classes (.btn-link, summaries) are unaffected. */
main a:not(.btn):not(.secondary):not(.btn-link):not(.logolink),
.link {
  color:var(--orange); text-decoration:underline; cursor:pointer;
}
main a:not(.btn):not(.secondary):not(.btn-link):not(.logolink):hover,
.link:hover { color:#cc5c00; }
main a.btn, main a.cancel, main a.secondary { text-decoration:none; }
h1 { color:var(--orange); font-size:1.3rem; margin:.4rem 0; }
h2 { color:var(--gray); font-size:1.05rem; margin:1rem 0 .4rem; }
.card { background:#fff; border:1px solid #ddd; border-radius:10px; padding:14px; margin:10px 0; }
label { display:block; font-size:.85rem; color:var(--gray); margin-top:8px; }
input, select, textarea { width:100%; padding:10px; margin-top:4px; border:1px solid #ccc; border-radius:8px; font:inherit; }

/* Inactive fields read as inactive — a disabled (e.g. Hours when a full day is
   selected) or auto-filled read-only field (e.g. an automatic mileage/per-diem
   rate) gets a grey fill and muted text so it's clearly not yours to type in. */
input:disabled, select:disabled, textarea:disabled,
input[readonly], textarea[readonly] {
  background:#f3f4f6; color:#8a8f98; cursor:not-allowed;
}
textarea { min-height:70px; }
button, .btn { background:var(--orange); color:#fff; border:none; border-radius:8px; padding:10px 16px; font-family:inherit; font-size:1rem; line-height:1.2; font-weight:bold; cursor:pointer; vertical-align:middle; }
button.secondary { font-size:1rem; font-weight:bold; padding:10px 16px; }
button.secondary { background:#fff; color:var(--gray); border:1px solid var(--gray); }
button.link { background:none; color:var(--orange); border:none; padding:4px; font-weight:normal; text-decoration:underline; }
table { width:100%; border-collapse:collapse; margin-top:8px; font-size:.92rem; }
/* Column headers pin below whatever chrome is showing (Bucket B #6). Stated
   ONCE globally rather than opted into screen by screen, which is safe only
   because every <th> in this app heads a COLUMN — there are no row-header th
   cells. A test guards that assumption across every template. */
th { background:var(--orange); color:#fff; text-align:left; padding:8px;
     position:sticky; top:var(--stickytop); z-index:20; }
td { padding:8px; border-bottom:1px solid #eee; vertical-align:top; }
tr:nth-child(even) td { background:var(--light); }
.flash { padding:10px 14px; border-radius:8px; margin:10px 0; }
.flash.ok { background:#eef9ee; border:1px solid #9ad29a; }
.flash.err { background:#fdeaea; border:1px solid #e09c9c; }
.flash.warn { background:#fff7e6; border:1px solid #f0c36d; }
.badge { font-size:.72rem; padding:2px 8px; border-radius:10px; background:var(--light); color:var(--gray); }
.badge.DRAFT { background:#eee; } .badge.CERTIFIED { background:#fff3e8; color:var(--orange); }
.badge.APPROVED { background:#eef9ee; color:#2c7a2c; } .badge.SENT_BACK { background:#fdeaea; color:#a33; }
.badge.receipt-missing { background:#fff7e6; border:1px solid #f0c36d; color:#9a6b00; }
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.row-actions form { display:inline; }
.devnote { font-size:.75rem; color:var(--gray); background:var(--light); padding:6px 10px; border-radius:6px; }
@media (max-width:640px){ .grid2{grid-template-columns:1fr;} th,td{font-size:.85rem; padding:6px;} nav{width:100%; justify-content:flex-start;} }

.logo { height:40px; display:block; }
.btn-link { color:var(--orange); font-size:.9rem; margin-left:10px; }
.periodgrid td { vertical-align:top; }
.periodgrid tr.weekend td { background:#fafafa; }
.inlineadd { display:flex; gap:6px; flex-wrap:wrap; margin-top:6px; }
.inlineadd select, .inlineadd input { width:auto; flex:1 1 120px; margin-top:0; }
.inlineadd input[name=description] { flex:3 1 240px; }
.inlineadd button { padding:8px 14px; }
.entryline { margin:4px 0; }
@media (max-width:640px){ .inlineadd select, .inlineadd input { flex-basis:100%; } .logo{height:32px;} }

tr.dim td { color:#999; }

.twocol { display:grid; grid-template-columns:2fr 1fr; gap:12px; align-items:start; }
@media (max-width:760px){ .twocol{grid-template-columns:1fr;} }
.totals .bignum { font-size:1.6rem; color:var(--orange); font-weight:bold; margin:.3rem 0; }
.totals .bignum span { font-size:.9rem; color:var(--gray); font-weight:normal; }
table.mini { font-size:.85rem; } table.mini td { padding:4px 6px; border-bottom:1px solid #f0f0f0; }
.btn.cancel { background:#fff; color:var(--gray); border:1px solid #ccc; text-decoration:none; padding:10px 16px; border-radius:8px; display:inline-block; }

/* wide screens for grid-heavy pages */
main.wide { max-width:96vw; }
/* import review table: one clean line per charge */
.importgrid th, .importgrid td { white-space:nowrap; padding:6px 8px; }
.importgrid select { width:auto; min-width:130px; margin-top:0; }
.importgrid input[type=text] { width:220px; margin-top:0; }
.importgrid input[type=number] { width:140px; margin-top:0; }
.importgrid input[type=date] { width:150px; margin-top:0; }
.importgrid input[type=file] { width:180px; margin-top:0; font-size:.8rem; }
.importgrid td.merch { white-space:normal; max-width:230px; }
/* The free-prose explanation column on the three import REVIEW screens.
   The blanket nowrap above is right for the data columns and wrong for this
   one: at S26-0818h the REFNO review screen's "What happens" column ran off
   the right edge and truncated every explanation mid-sentence, across 50
   rows. Three review screens render that cell, not one — same rule, same
   defect, so the exception is defined once and applied to all three.
   min-width, not max-width: the failure to avoid is a column squeezed to one
   word per line, which is a different way to be unreadable. */
.importgrid td.detail { white-space:normal; min-width:240px; }

/* ─────────────────────────────────────────────────────────────────────────
   Pinned chrome (Bucket B #6 — sticky nav + sticky table column headers)
   DR-21. Everything here was decided against a real browser measurement, not
   from reasoning about the spec. The two facts that shaped it:

   1. A wrapper with `overflow-x:auto` COMPUTES `overflow-y:auto` and so
      becomes a scroll container. `position:sticky` inside it resolves against
      that container instead of the window — and with no height limit the
      container never scrolls vertically, so the header row NEVER PINS and
      there is no error, no warning, and no server-side symptom to notice.
      MEASURED: a header row inside such a wrapper sat at y=-348px after a
      400px scroll, against y=+60px for the same table with no wrapper.
      `overflow-y:clip` does NOT rescue it — measured, same -348px. The only
      fix that works is capping the height so the wrapper is a REAL scroll box,
      which is what `.tablescroll` does below.
      This is why `.gridwrap` (formerly `overflow-x:auto`, no cap) is gone
      rather than kept: a class that silently disables sticky headers is a trap.

   2. The proxy banner (`_proxy_banner.html`) ALREADY pinned at top:0 before
      this feature existed, and it is a SAFETY control — it is what stops a
      controller entering their own time onto a field user's record. A header
      pinned at top:0 with a higher z-index hides it completely, and hides it
      exactly when the controller has scrolled to the save button, which is
      where that mistake happens. So the offsets are not two independent rules:
      `--navh` is the header, `--stickytop` is the header PLUS any pinned
      banner, and base.html is the ONE place that computes both.
   ───────────────────────────────────────────────────────────────────────── */

/* Pinned page chrome that sits BELOW the nav (currently the proxy banner).
   Anything that needs to stay on screen uses this class rather than pinning
   itself in an inline style, so the offset calculation can see it. */
.stickychrome { position:sticky; top:var(--navh); z-index:40; }

/* Keep BROWSER-INITIATED scrolling clear of the pinned chrome. Without this,
   anything the browser scrolls to lands at the very top of the viewport, which
   is now underneath the nav. MEASURED on the timesheet: scrollIntoView() put
   the target field at y=0 with 60px of nav on top of it — invisible. The case
   that matters is form validation: "please fill out this field" scrolls to a
   required field the operator then cannot see, on a form-heavy app where every
   screen is a form. Also covers anchor links and keyboard focus.
   The inner scroll window needs its own padding for its own pinned header row. */
html { scroll-padding-top:var(--stickytop); }
.tablescroll { scroll-padding-top:2.5rem; }

/* A wide and/or long data table in its own scroll window. Horizontal scroll
   always — the employee roster is 21 columns and will not fit. The height cap
   is what makes the pinned header row possible (see note 1 above), and it is
   desktop-only (see the phone block below). */
.tablescroll { overflow-x:auto; }

/* Inside a scroll window, sticky resolves against the WINDOW, so the offset is
   0. Using the page's chrome height here would push the header row down inside
   its own box and hide the first rows of data. */
.tablescroll th { top:0; }

@media (min-width:641px) {
  .tablescroll { overflow:auto; max-height:calc(100vh - var(--stickytop) - 24px); }

  /* ── #6 remainder (S26-0811a): pinned IDENTITY COLUMN + pinned TOTAL ROW ──
     Opt-in per table via `.pincol` / `.pinfoot`, NOT global like `th`. The
     global th rule is safe because every th here heads a column; there is no
     equivalent guarantee for column one — the import review grid's cells hold
     live selects and inputs. Cash's confirmed scope 8/11: report tables only.
     Verified first: all 34 report/view combinations lead with an identifying
     column (name / group / category / person / project / customer / Invoice #).

     THE Z-ORDER IS THE WHOLE DESIGN, and one step is easy to get backwards:
       header 60 > .stickychrome 40 > corner th 30 > th 20 > tfoot 15 > col 10
     The pinned column sits BELOW `th` (20). Rank it above and scrolling DOWN
     slides name cells over the column titles. Everything here stays below 40
     so a table cell can never cover the proxy safety banner — that banner is
     what stops a controller entering their own time onto a field user's
     record, and it is hidden exactly when they have scrolled to the save
     button (DR-21 note 2). */
  .pincol td:first-child { position:sticky; left:0; z-index:10;
                           background:#fff;
                           box-shadow:2px 0 4px rgba(0,0,0,.10); }
  .pincol th:first-child { position:sticky; left:0; z-index:30;
                           box-shadow:2px 0 4px rgba(0,0,0,.10); }

  /* OPACITY, PER ROW TYPE — the actual hard part. A transparent pinned cell
     lets the columns it covers scroll visibly through it. The header row got
     away with one colour because every th is orange; data rows paint FOUR
     different backgrounds. And `.pincol td:first-child` (0,2,1) OUT-SPECIFIES
     `tr:nth-child(even) td` (0,1,2), so without the three rules below every
     pinned cell would paint plain white and the stripe, the group header and
     the dark total row would each break alignment at column one.
     ORDER IS LOAD-BEARING: the emph and totalrow selectors have IDENTICAL
     specificity to the nth-child one, so source order is the only thing
     deciding what an emphasis row on an even index looks like. Most specific
     row type last. The plain-row white lives in the position rule above rather
     than here, so each of these selectors is declared EXACTLY ONCE — a guard
     pins that, because a split block makes the opacity check read whichever
     half came first and pass while the cell is transparent. */
  .pincol tr:nth-child(even) td:first-child { background:var(--light); }
  .pincol tr.emph td:first-child { background:#FBE9D8; }
  .pincol tr.totalrow td:first-child { background:var(--gray); }

  /* The total row pins to the BOTTOM of the scroll window. The height cap
     above is what gives it a bottom edge to pin against at all — without it
     there is no scroll box and this is a silent no-op, same as note 1. It
     stays UNDER `th`: when the box is too short for both, losing the total for
     one scroll position is recoverable, losing the column labels is not. */
  .pinfoot tfoot td { position:sticky; bottom:0; z-index:15;
                      box-shadow:0 -2px 4px rgba(0,0,0,.10); }

  /* One cell is sticky in TWO directions — the total row's first cell. It has
     to cover the rest of the total row going sideways and the rest of the
     pinned column going down, so it outranks both.
     IT MUST RESTATE BOTH SHADOWS. This selector out-specifies both
     single-direction rules above, and `box-shadow` REPLACES rather than merges
     across rules — declare one direction here and the corner silently loses the
     other edge, visible only when the table is scrolled both ways at once. */
  .pincol.pinfoot tfoot td:first-child { z-index:16;
                      box-shadow:2px 0 4px rgba(0,0,0,.10),
                                 0 -2px 4px rgba(0,0,0,.10); }
}

/* Phones: nothing pins. MEASURED — the header is 129px tall at 390px wide once
   the nav wraps onto its own full-width row, and pinning that costs a third of
   the visible screen. A height-capped table window inside what is left is worse
   than simply scrolling the page. A deliberate, stated limitation (DR-21), not
   an oversight; `--navh` collapses to 0 here because base.html only counts
   elements whose computed position is actually `sticky`. */
@media (max-width:640px) {
  header { position:static; }
  th { position:static; }
  .stickychrome { position:static; }
  /* The #6-remainder additions, unpinned explicitly rather than merely left
     out of the desktop block. Belt and braces: a future edit that hoists one
     of these to the top level still cannot pin a 390px screen. A pinned
     identity column on a phone is the same arithmetic DR-21 measured for the
     header — the roster's Name column is wide, and there is not enough
     horizontal room left to be worth the pin. */
  .pincol td:first-child { position:static; box-shadow:none; }
  .pincol th:first-child { position:static; box-shadow:none; }
  .pinfoot tfoot td { position:static; box-shadow:none; }
}

details.addmore summary { color:var(--orange); cursor:pointer; font-size:.88rem; margin:4px 0; }
details.addmore { margin-top:4px; }

/* Collapsible setup group (e.g. a client's billing entities) */
details.clientgroup { background:#fff; border:1px solid #ddd; border-radius:10px; padding:6px 14px; margin:10px 0; }
details.clientgroup > summary { cursor:pointer; font-weight:bold; font-size:1.05rem; color:var(--gray); padding:8px 0; list-style:none; }
details.clientgroup > summary::-webkit-details-marker { display:none; }
details.clientgroup > summary::before { content:'\25B8\00a0'; color:var(--orange); }
details.clientgroup[open] > summary::before { content:'\25BE\00a0'; }
details.clientgroup > summary .count { font-weight:normal; font-size:.85rem; color:var(--gray); }

/* destructive action (purge) */
button.link.danger { color:#c0392b; }

/* ── Reports: searchable-chip multiselect + sortable tables ── */
.msel { margin-top: 8px; }
.msel-box { border:1px solid #ccc; border-radius:8px; padding:6px; margin-top:4px; background:#fff; }
.msel-chips { display:flex; flex-wrap:wrap; gap:6px; }
.msel-chips:not(:empty) { margin-bottom:6px; }
.chip { display:inline-flex; align-items:center; gap:6px; background:var(--orange); color:#fff;
  border-radius:14px; padding:3px 10px; font-size:.82rem; font-weight:bold; }
.chip-x { cursor:pointer; font-weight:bold; line-height:1; opacity:.85; }
.chip-x:hover { opacity:1; }
.msel-search { width:100%; padding:7px 8px; border:1px solid #ddd; border-radius:6px; margin:0; }
.msel-list { max-height:170px; overflow-y:auto; margin-top:6px; }
.msel-opt { padding:6px 8px; border-radius:6px; cursor:pointer; font-size:.9rem; color:var(--dark); }
.msel-opt:hover { background:var(--light); }
.msel-opt.on { background:#FBE9D8; color:var(--orange); font-weight:bold; }
.msel-opt.on::before { content:"\2713  "; }

table.sortable th { user-select:none; white-space:nowrap; }
table.sortable th .sortarrow { font-size:.75rem; }
tr.emph td { font-weight:bold; background:#FBE9D8; }
tr.totalrow td { font-weight:bold; background:var(--gray); color:#fff; }
#tableFilter { display:block; }

/* ─────────────────────────────────────────────────────────────────────────
   Shared utility vocabulary (UX polish, step 1)
   Named classes that replace repeated inline style="…" across templates, so
   every screen uses one consistent treatment. Add classes here; adopt them
   on screens one at a time. No template is forced to change by their mere
   existence — these only take effect where applied.
   ───────────────────────────────────────────────────────────────────────── */

/* Badge intent variants — match the .flash.warn / .flash.ok semantics, for
   inline status chips (send-back "Fix" notes, "missing", "ready", etc.).
   Replaces repeated inline background/border on <span class="badge">. */
.badge.warn { background:#fff7e6; border:1px solid #f0c36d; color:#9a6b00; }
.badge.ok   { background:#e8f5e9; border:1px solid #7cb87f; color:#2c7a2c; }

/* Bulk-import row outcomes (the import review screen). create / update / error
   read as a traffic-light trio. Replaces inline background+color spans. */
.badge.create { background:#e6f4ea; color:#1e7a34; }
.badge.update { background:#eef0f3; color:var(--gray); }
.badge.error  { background:#fce8e6; color:#b3261e; }

/* Invoice lifecycle chips — deliberately emphatic SOLID fills (not the soft
   .ok/.warn tints), because a released invoice number is a final, load-bearing
   state. .badge.released = solid green; .badge.draft = solid brand orange. */
.badge.released { background:#2e7d32; color:#fff; }
.badge.draft    { background:var(--orange); color:#fff; }

/* Active selection chip — solid brand orange marking the currently-chosen
   option among sibling toggle links (e.g. the selected report view). */
.badge.active { background:var(--orange); color:#fff; }
.subtle { color:var(--gray); font-size:.85rem; }
p.subtle { margin:6px 0 10px; }

/* Muted / placeholder cell text (the "—" and "no entries" states). */
.muted { color:#999; }

/* Right-aligned numeric column — use on both the <th> and its <td>s so the
   header and the digits line up. Replaces inline text-align:right. */
.num { text-align:right; }
th.num, td.num { text-align:right; }

/* Section divider above a related group of fields/links. Replaces the
   repeated border-top + margin/padding-top inline rule. */
.divider-top { border-top:1px solid #eee; margin-top:14px; padding-top:12px; }

/* Checkbox-with-label row — a checkbox sitting inline beside its label text,
   the checkbox not stretched to full width. Replaces the repeated
   label{display:flex;align-items:center;gap:8px} + input{width:auto;margin:0}
   pair used across roles/grants/scope/option toggles (14+ places). */
.checkrow { display:flex; align-items:center; gap:8px; margin-top:6px; }
.checkrow input[type=checkbox] { width:auto; margin:0; }

/* Force uppercase input (2-letter state codes). */
.upper { text-transform:uppercase; }

/* Action-button intents (all share the base button shape) ------------------
   .btn.warn  — amber: a deliberate, recoverable override (e.g. "Close anyway"
                with exceptions outstanding — reopenable, so caution not alarm).
   .btn.danger — red: a destructive/irreversible action (matches purge).
   These work on <button> and on a.btn link-buttons. */
button.warn, .btn.warn {
  background:#fff; color:#9a6b00; border:1px solid #e0a93d;
}
button.warn:hover, .btn.warn:hover { background:#fff7e6; }
button.danger, .btn.danger {
  background:#fff; color:#c0392b; border:1px solid #d98b82;
}
button.danger:hover, .btn.danger:hover { background:#fdeaea; }

/* Per-diem day picker (Expenses) — the multi-day checkbox grid that appears
   when a DAYS-unit category is chosen. Relocated from an inline <style>. */
.daygrid  { display:grid; grid-template-columns:repeat(4,1fr); gap:4px; }
.daycheck { font-size:13px; display:flex; gap:4px; align-items:center; }

/* PO / budget estimate-month grid (Purchase Orders setup). Relocated from an
   inline <style>; collapses to 3 then 2 columns on narrow screens. */
.estgrid { display:grid; grid-template-columns:repeat(4,1fr); gap:8px 12px; margin-top:4px; }
.estcell { display:flex; flex-direction:column; font-size:.85em; color:var(--gray); gap:2px; }
.estcell span  { font-weight:600; }
.estcell input { width:100%; }
@media (max-width:780px) { .estgrid { grid-template-columns:repeat(3,1fr); } }
@media (max-width:560px) { .estgrid { grid-template-columns:repeat(2,1fr); } }

/* Build-tag footer (S26-0805d). Sits below every page's <main>, outside the
   signed-in gate, so the tag is readable on the sign-in screen too. Muted and
   small on purpose: it is provenance, not content, and it must not compete with
   the page. `--gray` rather than a literal so it tracks the brand. */
.buildfoot { margin-top:28px; padding:10px 16px; border-top:1px solid #e5e7eb;
             font-size:.72rem; letter-spacing:.5px; color:var(--gray);
             opacity:.75; text-align:center; }
