/* ──────────────────────────────────────────────────────────────────────
   Riglog design system — "calm, precise, native".
   One typeface (Inter), hairline borders, generous whitespace, GeoDrill
   blue only as accent. Brand layer stays swappable: tenant themes override
   the custom properties, never the components.
   ────────────────────────────────────────────────────────────────────── */

:root {
  --brand-primary: #0064AD;
  --brand-accent: #18B4E9;
  --brand-charcoal: #333E48;

  --rl-bg: #f7f8fa;
  --rl-surface: #ffffff;
  --rl-rail: #f1f3f6;
  --rl-text: #16191d;
  --rl-text-2: #5b6470;
  --rl-text-3: #646e7c;
  --rl-border: rgba(22, 25, 29, 0.10);
  --rl-border-2: rgba(22, 25, 29, 0.18);
  --rl-accent: var(--brand-primary);
  --rl-accent-soft: rgba(0, 100, 173, 0.08);
  --rl-danger: #c5283d;
  --rl-danger-soft: #fbeaec;
  --rl-warning: #976500;
  --rl-warning-soft: #fdf3dc;
  --rl-success: #1a7d4d;
  --rl-success-soft: #e6f4ec;
  --rl-chart-grid: rgba(22, 25, 29, 0.06);
  --rl-chart-fill: rgba(0, 100, 173, 0.07);
  --rl-radius: 10px;
  --rl-radius-lg: 14px;
  /* Spacing scale. There wasn't one, so 834 inline styles invented their own
     and the app shipped 5, 7, 9, 11, 13 and 22px as if each were a decision.
     New work uses these; the component values below are left at their tuned
     numbers rather than churned toward the nearest step. */
  --rl-space-1: 4px;
  --rl-space-2: 8px;
  --rl-space-3: 12px;
  --rl-space-4: 16px;
  --rl-space-5: 24px;
  --rl-space-6: 32px;
  --rl-space-7: 48px;
  /* Typography matches the GeoDrill Australia website: Inter for everything
     the eye reads as interface or prose, Barlow Condensed for headings. The
     fonts are LOADED in base.html — naming a family here without serving it
     is why the app rendered differently on every machine. */
  --rl-font: "Inter", -apple-system, "Segoe UI", system-ui, sans-serif;
  --rl-font-head: "Barlow Condensed", "Century Gothic", "Trebuchet MS", system-ui, sans-serif;
  /* Numerals read as instrument data, not prose ("Core Sample" direction) */
  --rl-mono: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, "Roboto Mono", monospace;
  /* Text that sits ON a filled accent. Light accents carry white; the dark
     theme's accents are light, so they carry ink instead. Components read
     this token and never spell the colour themselves — the workshop's
     success and danger fills were left out of the old per-component dark
     override and shipped white text at 2.13:1 and 3.49:1 because of it. */
  --rl-on-fill: #ffffff;
  --amma-orange: #F97316; /* Ammacatize mark — the A and i (AI) */
}

/* Dark is the default shell theme (set by the head script in base.html;
   light remains available from the header toggle). Palette is tuned to the
   foyer wall: #0c0f13 base, GeoDrill cyan #18B4E9 as the single accent. */
html[data-theme="dark"] {
  color-scheme: dark;
  /* "Core Sample": blue-steel greys biased toward the cyan accent — chosen
     neutrals, not flat black. Panels sit a step above the ground. */
  --rl-bg: #0C1218;
  --rl-surface: #10161D;
  --rl-rail: #0A0F14;
  --rl-text: #E6EDF3;
  --rl-text-2: #9FB0C0;
  --rl-text-3: #788d9f;
  --rl-border: rgba(159, 193, 221, 0.10);
  --rl-border-2: rgba(159, 193, 221, 0.20);
  --rl-accent: #18B4E9;
  --rl-accent-soft: rgba(24, 180, 233, 0.10);
  --rl-danger: #E2604C;
  --rl-danger-soft: rgba(226, 96, 76, 0.10);
  --rl-warning: #E8B94A;
  --rl-warning-soft: rgba(232, 185, 74, 0.13);
  --rl-success: #43C88C;
  --rl-success-soft: rgba(67, 200, 140, 0.13);
  --rl-chart-grid: rgba(230, 237, 243, 0.05);
  --rl-chart-fill: rgba(24, 180, 233, 0.08);
  /* Every dark-theme accent is light enough to need ink, not white. */
  --rl-on-fill: #08222c;
}

/* ── Base ── */
body.rl-body {
  background: var(--rl-bg);
  color: var(--rl-text);
  font-family: var(--rl-font);
  font-size: 14px;
  line-height: 1.55;
  letter-spacing: -0.006em;
  -webkit-font-smoothing: antialiased;
  margin: 0;
}
/* Dark-only depth: a faint cyan wash bleeding from the top edge, the same
   trick the foyer wall uses. Invisible in light mode. */
html[data-theme="dark"] body.rl-body {
  background:
    radial-gradient(1100px 480px at 72% -140px, rgba(24, 180, 233, 0.07), transparent 60%),
    var(--rl-bg);
  background-attachment: fixed;
}
html[data-theme="dark"] .rl-rail-item.active { box-shadow: 0 0 0 1px rgba(24, 180, 233, 0.12), 0 1px 8px rgba(0, 0, 0, 0.35); }
.rl-body h1, .rl-body h2, .rl-body h3, .rl-body h4 { font-weight: 600; letter-spacing: -0.015em; color: var(--rl-text); }
.rl-body a { color: var(--rl-accent); text-decoration: none; }
.rl-body a:hover { text-decoration: underline; }

/* ── App frame ── */
/* Practice-mode banner (pre-go-live play window). The offset variable is
   0 unless the banner is actually present, so the shell layout is untouched
   when it's off — and removing the banner needs no CSS change. */
.rl-practice {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 9px 16px; text-align: center;
  background: var(--rl-warning-soft); color: var(--rl-warning);
  border-bottom: 1px solid var(--rl-warning);
  font-size: 13.5px; font-weight: 600; line-height: 1.35;
}
.rl-practice i { font-size: 15px; flex: none; }
body:has(.rl-practice) { --rl-banner-h: 38px; }

.rl-app { display: flex; min-height: calc(100vh - var(--rl-banner-h, 0px)); }
.rl-rail {
  width: 232px; flex: none; background: var(--rl-rail);
  border-right: 1px solid var(--rl-border);
  padding: 18px 12px; display: flex; flex-direction: column; gap: 2px;
  position: sticky; top: var(--rl-banner-h, 0px);
  height: calc(100vh - var(--rl-banner-h, 0px)); overflow-y: auto;
}
.rl-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.rl-header {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 28px; border-bottom: 1px solid var(--rl-border);
  background: var(--rl-surface); position: sticky; top: 0; z-index: 50;
}
/* box-sizing matters here: `width: 100%` plus 28px of horizontal padding
   made the content box 28px wider than the viewport on every phone, and
   there is no global border-box reset to fall back on. */
.rl-content { box-sizing: border-box; padding: 26px 28px 48px; max-width: 1280px; width: 100%; margin: 0 auto; }

/* ── Rail ── */
.rl-logo { display: flex; align-items: center; gap: 10px; padding: 2px 10px 16px; }
.rl-logo-mark {
  width: 30px; height: 30px; border-radius: 8px; background: var(--brand-primary);
  /* Not --rl-on-fill: the mark sits on the tenant BRAND colour, which does not
     change with the theme, so white stays correct in both. */
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 15px; flex: none;
}
.rl-logo-mark img { width: 20px; height: 20px; display: block; }
.rl-logo-name { font-weight: 600; font-size: 14.5px; line-height: 1.15; }
.rl-logo-tenant { font-size: 11.5px; color: var(--rl-text-3); }
.rl-rail-close { margin-left: auto; flex: none; }
.rl-rail-section {
  padding: 14px 10px 5px; font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--rl-text-3);
}
/* .rl-app prefix outweighs the `.rl-body a` accent rule — rail links stay muted. */
.rl-app .rl-rail-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7.5px 10px; border-radius: 8px;
  color: var(--rl-text-2); font-weight: 500; font-size: 13.5px;
  text-decoration: none !important; cursor: pointer;
}
/* Some rail items (reset, sign-out) are <button>s, not <a>s. The rule above
   only sets layout and colour, so without this a button still shows UA
   chrome — border, grey face, system font — in a rail of flush, borderless
   rows. There's no global button reset to fall back on. */
.rl-app button.rl-rail-item {
  width: 100%; font: inherit; border: 0; background: transparent; text-align: left;
}
.rl-rail-item i { font-size: 16px; width: 18px; text-align: center; flex: none; }
.rl-rail-item:hover { background: var(--rl-accent-soft); color: var(--rl-text); }
.rl-rail-item.active { background: var(--rl-surface); color: var(--rl-text); border: 1px solid var(--rl-border); box-shadow: 0 1px 2px rgba(16,19,23,0.04); }
.rl-rail-item.active i { color: var(--rl-accent); }
.rl-rail-item.locked { color: var(--rl-text-3); cursor: default; }
.rl-rail-item.locked:hover { background: transparent; color: var(--rl-text-3); }
.rl-soon {
  margin-left: auto; font-size: 9.5px; font-weight: 600; letter-spacing: 0.05em;
  background: var(--rl-accent-soft); color: var(--rl-accent);
  padding: 2px 7px; border-radius: 99px; text-transform: uppercase;
}

/* ── Header ── */
.rl-search {
  display: flex; align-items: center; gap: 8px; flex: 1; max-width: 460px;
  border: 1px solid var(--rl-border); border-radius: 9px;
  padding: 7px 12px; color: var(--rl-text-3); background: var(--rl-bg);
}
.rl-search input { border: 0; outline: 0; background: transparent; flex: 1; font: inherit; color: var(--rl-text); }
/* Drawer chrome: off by default, switched on inside the ≤860px block below.
   Order and specificity both matter here, in opposite directions, and getting
   either wrong is silent:
     - declared AFTER that block, an equally specific rule wins and the menu
       handle the whole mobile navigation hangs off never appears;
     - declared as a bare `.rl-navbtn`, `.rl-btn { display: inline-flex }`
       further down wins on source order and the handle appears on DESKTOP.
   `.rl-btn.rl-navbtn` out-specifies the button rule; the ≤860px block matches
   it selector for selector. */
.rl-btn.rl-navbtn { display: none; }
.rl-scrim { display: none; }

.rl-avatar {
  width: 32px; height: 32px; border-radius: 50%; background: var(--rl-accent-soft);
  color: var(--rl-accent); display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 600; flex: none;
}

/* ── Page scaffolding ── */
.rl-page-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 22px; flex-wrap: wrap; }
.rl-page-title { font-size: 21px; margin: 0; }
.rl-page-sub { color: var(--rl-text-2); font-size: 13px; margin: 3px 0 0; }
.rl-page-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* ── Cards & stats ── */
.rl-card {
  background: var(--rl-surface); border: 1px solid var(--rl-border);
  border-radius: var(--rl-radius-lg); padding: 18px 20px;
}
.rl-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; margin-bottom: 24px; }
.rl-stat {
  background: linear-gradient(180deg, var(--rl-surface), var(--rl-bg) 160%);
  border: 1px solid var(--rl-border); border-radius: var(--rl-radius-lg); padding: 14px 16px;
}
.rl-stat-label {
  font-size: 10.5px; color: var(--rl-text-3); font-weight: 600;
  letter-spacing: 0.11em; text-transform: uppercase;
}
.rl-stat-value {
  font-size: 25px; font-weight: 600; letter-spacing: -0.02em; margin-top: 5px;
  font-family: var(--rl-mono); font-variant-numeric: tabular-nums;
}
.rl-stat-hint { font-size: 11.5px; color: var(--rl-text-3); margin-top: 3px; }
/* A figure the platform is suppressing rather than guessing. It must not read
   as a value — the whole point is that there isn't one — so it drops to the
   muted foreground and lets the hint underneath carry the reason. */
.rl-stat-value.rl-stat-none { color: var(--rl-text-3); font-weight: 400; }
.rl-stat-value.danger { color: var(--rl-danger); }
.rl-stat-value.warning { color: var(--rl-warning); }
.rl-stat-value.success { color: var(--rl-success); }
/* The one figure the page leads with — a single cyan-carried hero KPI. */
.rl-stat.hero { border-color: rgba(24, 180, 233, 0.35); box-shadow: 0 0 0 1px rgba(24, 180, 233, 0.12), 0 10px 26px -20px var(--rl-accent); }
.rl-stat.hero .rl-stat-value { color: var(--rl-accent); }

/* ── Lists / tables ── */
/* overflow-x:auto, NOT hidden: `hidden` clipped every wide table on a phone
   with no way to reach the cut-off columns (the workshop runs this on phones —
   35 list screens were affected). `.rl-list` has no height constraint, so
   overflow-y never triggers and no vertical scrollbar appears; the radius
   still clips. */
.rl-list { background: var(--rl-surface); border: 1px solid var(--rl-border); border-radius: var(--rl-radius-lg); overflow-x: auto; }
.rl-list-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px; border-bottom: 1px solid var(--rl-border);
  font-weight: 600; font-size: 13.5px;
}
table.rl-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.rl-table th {
  text-align: left; font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--rl-text-3);
  padding: 10px 18px; border-bottom: 1px solid var(--rl-border);
}
.rl-table td { padding: 11px 18px; border-bottom: 1px solid var(--rl-border); vertical-align: middle; }
.rl-table tbody tr:last-child td { border-bottom: 0; }
.rl-table tbody tr { cursor: default; }
.rl-table tbody tr[data-href] { cursor: pointer; }
.rl-table tbody tr[data-href]:hover { background: var(--rl-accent-soft); }
.rl-table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--rl-mono); font-size: 12.5px; }
/* Read-only data tables (performance pages): quiet row highlight on hover. */
.rl-table.rl-hover tbody tr:hover td { background: var(--rl-accent-soft); }

/* ── In-cell margin bar (Project P&L GP column) ──
   A hairline of data-ink under the number: filled to the margin %, coloured
   by health. The number stays primary; the bar makes the column scannable. */
.rl-gpcell { position: relative; }
.rl-gpcell .rl-gpbar {
  position: absolute; left: 18px; right: 18px; bottom: 5px; height: 2px;
  background: var(--rl-border); border-radius: 2px; overflow: hidden;
}
.rl-gpbar i { display: block; height: 100%; border-radius: 2px; background: var(--rl-success); }
.rl-gpbar i.warn { background: var(--rl-warning); }
.rl-gpbar i.crit { background: var(--rl-danger); }

/* ── A figure the platform is withholding ──
   `.rl-nofig` is the dash on its own; `.rl-why` is the dash plus the reason,
   disclosed in place. The reason was previously a `title`, which does not
   exist on a phone and never printed — see performance/_no_figure.html.
   Numeric columns are right-aligned, so the opened reason flips back to
   left-aligned prose: a wrapped sentence set ragged-left is unreadable. */
.rl-nofig { color: var(--rl-text-3); }
/* The short-reason variant: the reason is a few words, so it just sits next
   to the dash rather than earning a disclosure. */
.rl-nofig-why { font-size: 11px; color: var(--rl-text-3); white-space: normal; }
.rl-why { display: inline-block; text-align: right; }
.rl-why > summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: baseline; gap: 5px;
  color: var(--rl-text-3);
}
.rl-why > summary::-webkit-details-marker { display: none; }
.rl-why > summary:focus-visible {
  outline: 2px solid var(--rl-accent); outline-offset: 2px; border-radius: 4px;
}
/* The cue is what makes the dash look answerable rather than empty. */
.rl-why-cue {
  font-family: var(--rl-font); font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--rl-accent); border-bottom: 1px solid currentColor;
}
.rl-why[open] > summary .rl-why-cue { color: var(--rl-text-3); }
.rl-why-body {
  display: block; margin-top: 6px; max-width: 34ch;
  font-family: var(--rl-font); font-size: 11.5px; font-weight: 400;
  line-height: 1.5; text-align: left; white-space: normal;
  color: var(--rl-text-2);
}
/* A closed <details> cannot be forced open from CSS — neither `display` nor
   `content-visibility` on its body reaches through the slot, verified in
   Chrome. So print swaps the disclosure for a plain copy of the reason
   rather than trying to prise the real one open and silently printing a bare
   dash. See performance/_no_figure.html. */
.rl-why-print { display: none; }
@media print {
  .rl-why { display: none; }
  .rl-why-print {
    display: block; max-width: none; text-align: left; white-space: normal;
    font-family: var(--rl-font); font-size: 11px; font-weight: 400; line-height: 1.45;
  }
}

/* ── Status ── */
.rl-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 7px; vertical-align: 1px; }
.rl-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; font-weight: 600; padding: 3px 10px; border-radius: 99px;
}
.rl-pill.ok, .rl-pill.active, .rl-pill.closed, .rl-pill.completed { background: var(--rl-success-soft); color: var(--rl-success); }
.rl-pill.warn, .rl-pill.due, .rl-pill.maintenance, .rl-pill.in_progress { background: var(--rl-warning-soft); color: var(--rl-warning); }
.rl-pill.bad, .rl-pill.overdue, .rl-pill.down { background: var(--rl-danger-soft); color: var(--rl-danger); }
.rl-pill.muted, .rl-pill.upcoming, .rl-pill.raised, .rl-pill.assigned, .rl-pill.sold, .rl-pill.retired, .rl-pill.cancelled { background: var(--rl-accent-soft); color: var(--rl-text-2); }

/* ── Buttons & forms ── */
.rl-btn {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-weight: 550; font-size: 13px;
  padding: 7.5px 14px; border-radius: 9px; cursor: pointer;
  border: 1px solid var(--rl-border-2); background: var(--rl-surface); color: var(--rl-text);
  text-decoration: none !important; transition: background 0.12s ease, transform 0.05s ease;
}
.rl-btn:hover { background: var(--rl-bg); }
.rl-btn:active { transform: scale(0.98); }
.rl-btn.primary { background: var(--rl-accent); border-color: var(--rl-accent); color: var(--rl-on-fill); }
.rl-btn.primary:hover { filter: brightness(1.07); background: var(--rl-accent); }
.rl-btn.danger { color: var(--rl-danger); border-color: var(--rl-danger); }
/* Paired with .danger on start/stop actions — go and stop read at a glance. */
.rl-btn.success { color: var(--rl-success); border-color: var(--rl-success); }
.rl-btn.sm { padding: 4.5px 10px; font-size: 12px; border-radius: 7px; }

/* ── Focus ──
   `.rl-search input` and the filter controls set `outline: 0` and put nothing
   back, so on every page in the app the keyboard cursor simply vanished. One
   treatment for everything that is clicked rather than typed into; typed
   controls keep the ring-and-border pair defined with them. The accent
   carries 6.1:1 (light) and 7.6:1 (dark) against the surfaces it lands on, so
   the indicator itself clears the 3:1 floor. */
.rl-btn:focus-visible,
.rl-w-btn:focus-visible,
.rl-w-step:focus-visible,
.rl-w-row:focus-visible,
.rl-w-back:focus-visible,
.rl-rail-item:focus-visible,
.rl-launch-tile:focus-visible,
.rl-table a:focus-visible,
.rl-body a:focus-visible,
.rl-fb-card h3 a:focus-visible {
  outline: 2px solid var(--rl-accent); outline-offset: 2px; border-radius: 8px;
}
/* The search input is borderless inside a bordered shell, so the shell takes
   the focus treatment — a ring on the input alone would float unattached. */
.rl-search:focus-within { border-color: var(--rl-accent); box-shadow: 0 0 0 3px var(--rl-accent-soft); }
.rl-filters select:focus-visible, .rl-filters input:focus-visible,
.rl-asst-voice:focus-visible {
  border-color: var(--rl-accent); box-shadow: 0 0 0 3px var(--rl-accent-soft);
}

.rl-field { margin-bottom: 14px; }
.rl-field label { display: block; font-size: 12.5px; font-weight: 550; margin-bottom: 5px; color: var(--rl-text-2); }
/* Form controls do NOT inherit the page font by default — browsers give them
   their own (Arial-ish) default. Any input outside .rl-field was therefore
   rendering in a different face from the page around it, which is why the
   typography looked inconsistent field to field. Set it once, globally. */
input, select, textarea, button, optgroup {
  font-family: var(--rl-font);
}

/* Headings carry the GeoDrill display face. Condensed and slightly tighter,
   exactly as the website sets them. */
h1, h2, h3, .rl-page-title {
  font-family: var(--rl-font-head);
  font-weight: 600;
  letter-spacing: -0.015em;
}

.rl-input, .rl-field input[type="text"], .rl-field input[type="number"], .rl-field input[type="date"],
.rl-field input[type="datetime-local"], .rl-field input[type="email"], .rl-field input[type="password"],
.rl-field input[type="file"], .rl-field select, .rl-field textarea {
  width: 100%; box-sizing: border-box; font: inherit; color: var(--rl-text);
  background: var(--rl-surface); border: 1px solid var(--rl-border-2);
  border-radius: 9px; padding: 8px 11px; outline: none;
}
.rl-field input:focus, .rl-field select:focus, .rl-field textarea:focus, .rl-input:focus {
  border-color: var(--rl-accent); box-shadow: 0 0 0 3px var(--rl-accent-soft);
}
.rl-error { color: var(--rl-danger); font-size: 12.5px; margin-top: 4px; }
.rl-help { color: var(--rl-text-3); font-size: 12px; margin-top: 4px; }

/* ── Home module launcher — the shell's sections as titled tile groups.
   Renders from shell_sections, so it is role- and permission-filtered the
   same way the rail is: a user only sees the groups they can enter. ── */
.rl-launcher { display: grid; gap: 20px; margin-bottom: 28px; }
.rl-launch-title {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--rl-text-3); margin-bottom: 8px;
}
.rl-launch-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 8px; }
.rl-launch-tile {
  display: flex; align-items: center; gap: 10px; padding: 12px 14px;
  background: var(--rl-surface); border: 1px solid var(--rl-border);
  border-radius: var(--rl-radius); color: var(--rl-text);
  font-weight: 550; font-size: 13px; text-decoration: none !important;
}
.rl-launch-tile i { font-size: 17px; color: var(--rl-accent); flex: none; }
.rl-launch-tile:hover { border-color: var(--rl-border-2); background: var(--rl-accent-soft); }

/* ── Collapsible groups (rail sections + home launcher) ──
   Native <details>: keyboard- and screen-reader-accessible for free; the
   chevron mirrors state and the choice persists per user (base.html JS). */
.rl-rail-group > summary, .rl-launch-group > summary {
  cursor: pointer; user-select: none; list-style: none;
  display: flex; align-items: center; gap: 6px;
}
.rl-rail-group > summary::-webkit-details-marker,
.rl-launch-group > summary::-webkit-details-marker { display: none; }
.rl-rail-group > summary:focus-visible, .rl-launch-group > summary:focus-visible {
  outline: 2px solid var(--rl-accent); outline-offset: 2px; border-radius: 4px;
}
.rl-collapse-chev {
  margin-left: auto; font-size: 10px; color: var(--rl-text-3);
  transition: transform 0.15s ease;
}
details:not([open]) > summary .rl-collapse-chev { transform: rotate(-90deg); }
/* Collapsed rail groups keep a little rhythm between headings. */
.rl-rail-group { margin: 0; }
.rl-rail-group > summary.rl-rail-section { padding-right: 10px; }

/* ── Reorderable rail sections ──
   The wrapper repeats the rail's own column layout so inserting it between
   .rl-rail and its groups changes nothing visually. */
#rl-rail-sections { display: flex; flex-direction: column; gap: 2px; }
.rl-rail-grip {
  border: 0; background: transparent; cursor: grab; line-height: 1;
  color: var(--rl-text-3); opacity: 0; transition: opacity 0.12s ease;
  /* Same problem as the hold-to-talk mic (.rl-asst-mic): without this, a
     vertical drag from the grip is indistinguishable from a scroll, and
     .rl-rail is overflow-y: auto — the browser claims the gesture as a
     scroll and fires pointercancel before the drag ever starts. */
  touch-action: none;
  /* The icon is 12px; padding brings the hit target to 24x24 (WCAG 2.5.8)
     without growing the icon itself, and the matching negative margin
     keeps the heading's spacing exactly as it was — only the hit area
     grows, not the visible glyph or the layout around it. */
  padding: 6px; margin: -6px -4px -6px -6px;
}
.rl-rail-grip i { font-size: 12px; display: block; }
/* Revealed on hover, but always visible once focused — a keyboard user has
   no hover, and an invisible focused control is an unusable one. */
.rl-rail-group:hover .rl-rail-grip,
.rl-rail-grip:focus-visible { opacity: 1; }
.rl-rail-grip:focus-visible {
  outline: 2px solid var(--rl-accent); outline-offset: 2px; border-radius: 3px;
}
.rl-rail-group.rl-dragging { opacity: 0.6; }
.rl-rail-group.rl-dragging .rl-rail-grip { cursor: grabbing; opacity: 1; }
@media (hover: none) {
  /* No hover on a tablet — the grip has to be there to be grabbed. */
  .rl-rail-grip { opacity: 1; }
}

/* ── Filter bar ── */
.rl-filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }
.rl-filters select, .rl-filters input {
  font: inherit; font-size: 13px; color: var(--rl-text);
  background: var(--rl-surface); border: 1px solid var(--rl-border-2);
  border-radius: 8px; padding: 6.5px 10px; outline: none;
}

/* ── Misc ── */

/* The `hidden` attribute must actually hide.
   The UA stylesheet's [hidden]{display:none} is an author-overridable
   default, so ANY class that sets `display` silently beats it and the
   element stays on screen while `el.hidden === true`. That is not
   theoretical here: .rl-w-offline is display:flex, so the workshop's
   "You're offline" banner sat on every page of /w/ permanently, telling
   crews they had no connection while they were plainly online — and
   .rl-w-queued (display:flex) meant the queued-count chip never hid
   either. .rl-asst carries a one-off patch for the same collision, which
   is the tell that this needed solving once, centrally.
   !important is deliberate: the whole point is to outrank a class. */
[hidden] { display: none !important; }

/* Announced, never shown — live regions and skip targets. */
.rl-sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* ── The handful of patterns the templates kept re-typing ──
   These earn a name because they were spelled out inline dozens of times
   each, which is how a colour drifts: an inline style cannot be re-themed. */
.rl-muted { color: var(--rl-text-3); }
.rl-quiet { color: var(--rl-text-2); }
/* Link colour is set through a descendant selector, so a muted link has to
   out-specify it. */
.rl-body a.rl-muted { color: var(--rl-text-3); }
.rl-body a.rl-quiet { color: var(--rl-text-2); }
.rl-nowrap { white-space: nowrap; }
.rl-tnum { font-variant-numeric: tabular-nums; }
/* A whole row or tile that is one link, carrying no link styling of its own.
   Both rules are needed. `.rl-body a` sets the accent colour at (0,1,1), so
   the unscoped class alone would lose and every one of these would turn blue
   — the inline style it replaces never had to out-specify anything. The
   unscoped rule still earns its place: the project portal does not put
   `.rl-body` on its <body>, so only that one reaches its cards. */
.rl-bare-link { display: block; text-decoration: none !important; color: inherit; }
.rl-body a.rl-bare-link { color: inherit; }
.rl-stack { display: flex; flex-direction: column; gap: var(--rl-space-4); }

.rl-empty { padding: 38px 20px; text-align: center; color: var(--rl-text-3); font-size: 13.5px; }
.rl-empty i { font-size: 26px; display: block; margin-bottom: 8px; }
.rl-flash { border-radius: var(--rl-radius); padding: 11px 16px; margin-bottom: 16px; font-size: 13.5px; border: 1px solid; }
.rl-flash.success { background: var(--rl-success-soft); color: var(--rl-success); border-color: transparent; }
.rl-flash.error, .rl-flash.danger { background: var(--rl-danger-soft); color: var(--rl-danger); border-color: transparent; }
.rl-flash.info, .rl-flash.warning { background: var(--rl-warning-soft); color: var(--rl-warning); border-color: transparent; }
/* min() not a bare 330px: auto-fit will not shrink a track below its floor,
   so on a 320px phone the 292px content box overflowed sideways. */
/* ── Notice ──
   Four pages carried a 3px coloured `border-left` inline on an .rl-card to
   flag a held or stale figure. A thick side rule is the cheapest possible
   way to say "this one is different"; a tinted bed with a full hairline in
   the state colour says it around the whole block, which is what the notice
   actually means. The body stays --rl-text (15:1 on the tint) because these
   run to three or four lines of explanation and are meant to be read; the
   state is carried by the bed and the icon, not by tinting a paragraph. */
.rl-notice {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 13px 16px; margin-bottom: var(--rl-space-5);
  border: 1px solid var(--rl-border-2); border-radius: var(--rl-radius-lg);
  background: var(--rl-surface); color: var(--rl-text);
  font-size: 13px; line-height: 1.55;
}
.rl-notice > i { flex: none; margin-top: 1px; font-size: 15px; color: var(--rl-text-3); }
.rl-notice.warn { background: var(--rl-warning-soft); border-color: var(--rl-warning); }
.rl-notice.warn > i { color: var(--rl-warning); }
.rl-notice.bad { background: var(--rl-danger-soft); border-color: var(--rl-danger); }
.rl-notice.bad > i { color: var(--rl-danger); }

/* Style hooks that named themselves and were then styled inline anyway —
   a class that promises to be in the system and is not. */
.rl-gantt-controls {
  display: flex; gap: var(--rl-space-2); align-items: flex-end;
  flex-wrap: wrap; margin-bottom: var(--rl-space-3);
}
.rl-gantt-controls label { font-size: 11px; color: var(--rl-text-3); }
.rl-gantt-controls .rl-input { display: block; }
.rl-note { font-size: 12px; color: var(--rl-warning); margin: 0 0 var(--rl-space-3); }
/* The dash lines up with the numerals in the column it sits under. */
.rl-why-dash { font-family: var(--rl-mono); }

.rl-grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr)); gap: 16px; }
.rl-kv { width: 100%; font-size: 13.5px; }
.rl-kv td { padding: 6px 0; }
.rl-kv td:first-child { color: var(--rl-text-2); width: 42%; }

/* ── Assistant panel ── */
.rl-asst {
  position: fixed; right: 18px; bottom: 18px; z-index: 200;
  width: 360px; max-width: calc(100vw - 24px); height: 480px; max-height: calc(100vh - 36px);
  display: flex; flex-direction: column;
  background: var(--rl-surface); border: 1px solid var(--rl-border-2);
  border-radius: var(--rl-radius-lg); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}
/* The `hidden` attribute is how the panel closes — an author display rule
   would otherwise override it and the panel could never be dismissed. */
.rl-asst[hidden] { display: none; }
.rl-asst-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-bottom: 1px solid var(--rl-border); font-size: 13.5px;
}
.rl-asst-head .rl-btn:first-of-type { margin-left: auto; }
.rl-asst-status { font-size: 11.5px; color: var(--rl-text-3); }
.rl-asst-voice {
  margin-left: auto; max-width: 140px;
  font: inherit; font-size: 11.5px; color: var(--rl-text-2);
  background: var(--rl-bg); border: 1px solid var(--rl-border-2);
  border-radius: 7px; padding: 3px 6px; outline: none; cursor: pointer;
}
/* When the voice picker is visible it owns the right-push; cancel the button's
   auto-margin so the group isn't double-gapped. When the picker is hidden (no
   voices installed) this doesn't match, so the button still pushes right. */
.rl-asst-head .rl-asst-voice:not([hidden]) ~ .rl-btn:first-of-type { margin-left: 0; }
.rl-asst-log { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.rl-asst-msg {
  max-width: 85%; padding: 8px 12px; border-radius: 12px;
  font-size: 13.5px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: break-word;
}
.rl-asst-msg.user { align-self: flex-end; background: var(--rl-accent); color: var(--rl-on-fill); border-bottom-right-radius: 4px; }
.rl-asst-msg.assistant { align-self: flex-start; background: var(--rl-bg); border: 1px solid var(--rl-border); border-bottom-left-radius: 4px; }
.rl-asst-msg.error { color: var(--rl-danger); border-color: var(--rl-danger-soft); }
.rl-asst-msg.pending { color: var(--rl-text-3); }
.rl-asst-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-top: 1px solid var(--rl-border);
}
.rl-asst-bar input {
  flex: 1; min-width: 0; font: inherit; font-size: 13.5px; color: var(--rl-text);
  background: var(--rl-bg); border: 1px solid var(--rl-border-2);
  border-radius: 9px; padding: 8px 11px; outline: none;
}
.rl-asst-bar input:focus { border-color: var(--rl-accent); box-shadow: 0 0 0 3px var(--rl-accent-soft); }
.rl-asst-mic {
  flex: none; width: 40px; height: 40px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--rl-border-2); background: var(--rl-surface);
  color: var(--rl-accent); font-size: 17px;
  display: flex; align-items: center; justify-content: center;
  /* Hold-to-talk: the press must not become a scroll/long-press gesture. */
  touch-action: none; -webkit-user-select: none; user-select: none;
}
.rl-asst-mic.live {
  background: var(--rl-danger); border-color: var(--rl-danger); color: var(--rl-on-fill);
  animation: rl-asst-pulse 1.2s ease-in-out infinite;
}
/* While recording the ring tracks your actual voice level (--rl-level, 0–1),
   so "it isn't hearing me" is visible instead of guessed. The timed pulse
   above covers the moment before the meter reports. */
.rl-asst-mic.live[style*="--rl-level"] {
  animation: none;
  box-shadow: 0 0 0 calc(var(--rl-level, 0) * 14px) var(--rl-danger-soft);
  transition: box-shadow 80ms linear;
}
@keyframes rl-asst-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--rl-danger-soft); }
  50% { box-shadow: 0 0 0 9px transparent; }
}
@media (max-width: 600px) {
  .rl-asst { right: 8px; bottom: 8px; height: 70vh; }
  /* A bigger target on a phone — hit it with a knuckle, gloves on. */
  .rl-asst-mic { width: 52px; height: 52px; font-size: 20px; }
}

/* ── Powered by Ammacatize ── */
.rl-powered { font-size: 10.5px; color: var(--rl-text-3); }
.rl-powered-mark { color: var(--rl-text-2) !important; font-weight: 600; text-decoration: none !important; }
.rl-powered-mark span { color: var(--amma-orange); }
.rl-powered-footer { display: block; text-align: center; padding: 28px 0 0; }

/* ── Touch sizing ──
   Keyed on the POINTER, not the viewport: a 13" laptop with a touchscreen
   needs the big target and a 1280px mouse-driven desk does not. Density on
   desktop is deliberate, so this never fires there. */
@media (pointer: coarse) {
  .rl-btn { min-height: 44px; }
  .rl-btn.sm { min-height: 44px; padding: 4.5px 12px; }
  .rl-rail-item { min-height: 44px; }
  .rl-filters select, .rl-filters input { min-height: 44px; }
  .rl-launch-tile { min-height: 52px; }
}

/* ── Mobile navigation (≤860px) ──
   The rail was `display: none` here with nothing put in its place, so on a
   phone the app had no navigation at all — and `shell_back_url` is derived
   from the Referer, so a bookmark, a typed URL or a notification opened a
   screen with no way off it.

   The same <aside> becomes the drawer rather than a second menu beside it:
   one nav means one set of permission filtering and one active state, with
   nothing to drift apart. The rail's own markup is untouched. */
@media (max-width: 860px) {
  .rl-rail {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 210;
    width: min(302px, 86vw); height: 100%;
    padding-top: max(18px, env(safe-area-inset-top, 0px));
    padding-bottom: max(18px, env(safe-area-inset-bottom, 0px));
    transform: translateX(-100%);
    transition: transform 0.24s cubic-bezier(0.32, 0.72, 0, 1);
    box-shadow: 0 0 44px rgba(0, 0, 0, 0.45);
    overscroll-behavior: contain;
  }
  .rl-rail[data-open] { transform: translateX(0); }
  .rl-scrim {
    position: fixed; inset: 0; z-index: 205;
    background: rgba(6, 10, 14, 0.55);
    opacity: 0; pointer-events: none;
    transition: opacity 0.24s ease;
  }
  .rl-scrim[data-open] { opacity: 1; pointer-events: auto; }
  /* The drawer carries the brand and the sign-out, so the header sheds the
     identity chip to leave room for a usable search field at 320px. */
  .rl-userchip { display: none; }
  .rl-btn.rl-navbtn { display: inline-flex; }
  .rl-scrim { display: block; }
  .rl-header { padding: 10px 14px; gap: 8px; }
  .rl-search { min-width: 0; }
  .rl-content { padding: 18px 14px 40px; }
}


/* ──────────────────────────────────────────────────────────────────────
   Workshop mode — mobile-first, glove-and-sunlight UI (/w/).
   Huge tap targets, maximum contrast, minimal text per screen.
   Reuses the rl tokens above; no new colours.
   ────────────────────────────────────────────────────────────────────── */
.rl-w { max-width: 480px; margin: 0 auto; }
.rl-w-title { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 4px; }
.rl-w-sub { font-size: 15px; color: var(--rl-text-2); margin: 0 0 18px; }
.rl-w-label {
  display: block; font-size: 13px; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--rl-text-2); margin: 18px 0 8px;
}
/* A <label> can name one control; a set of radios needs a fieldset and its
   legend. The class carries the same look on span, label, legend or heading,
   so the markup is free to be whichever of those is actually true. */
.rl-w-fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
legend.rl-w-label { padding: 0; }
h2.rl-w-label { margin: 18px 0 8px; }

.rl-w-grid { display: grid; gap: 14px; margin: 16px 0; }

.rl-w-btn {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  width: 100%; box-sizing: border-box; min-height: 64px;
  font: inherit; font-size: 17px; font-weight: 600; line-height: 1.3;
  padding: 12px 18px; border-radius: 14px; cursor: pointer;
  border: 1px solid var(--rl-border-2); background: var(--rl-surface); color: var(--rl-text);
  text-decoration: none !important; text-align: center;
}
.rl-w-btn i { font-size: 22px; flex: none; }
.rl-w-btn:active { transform: scale(0.98); }
.rl-w-btn.primary { background: var(--rl-accent); border-color: var(--rl-accent); color: var(--rl-on-fill); }
.rl-w-btn.danger { background: var(--rl-danger); border-color: var(--rl-danger); color: var(--rl-on-fill); }
.rl-w-btn.success { background: var(--rl-success); border-color: var(--rl-success); color: var(--rl-on-fill); }
/* An action that exists but isn't available yet — rendered as a div, so it is
   neither tappable nor focusable; the label carries the reason. */
.rl-w-btn.disabled {
  background: transparent; color: var(--rl-text-3);
  border-style: dashed; cursor: default; font-weight: 500;
}
.rl-w-btn.disabled:active { transform: none; }

.rl-w-badge {
  min-width: 28px; height: 28px; padding: 0 8px; border-radius: 99px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--rl-danger); color: var(--rl-on-fill); font-size: 14px; font-weight: 700;
}
.rl-w-btn.primary .rl-w-badge, .rl-w-btn.danger .rl-w-badge { background: var(--rl-on-fill); color: var(--rl-danger); }

/* Huge numeric display input (meter readings, hours) */
.rl-w-num {
  width: 100%; box-sizing: border-box;
  font: inherit; font-size: 34px; font-weight: 600; text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--rl-text); background: var(--rl-surface);
  border: 1px solid var(--rl-border-2); border-radius: 14px;
  padding: 14px 16px; outline: none;
}
.rl-w-num:focus { border-color: var(--rl-accent); box-shadow: 0 0 0 4px var(--rl-accent-soft); }

/* Big search / manual-entry input */
.rl-w-search {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 18px;
  color: var(--rl-text); background: var(--rl-surface);
  border: 1px solid var(--rl-border-2); border-radius: 14px;
  min-height: 56px; padding: 12px 16px; outline: none;
}
.rl-w-search:focus { border-color: var(--rl-accent); box-shadow: 0 0 0 4px var(--rl-accent-soft); }

/* Big list rows */
.rl-w-rows {
  background: var(--rl-surface); border: 1px solid var(--rl-border);
  border-radius: 14px; overflow: hidden; margin: 16px 0;
}
.rl-w-row {
  display: flex; align-items: center; gap: 14px;
  min-height: 56px; padding: 12px 16px;
  border-bottom: 1px solid var(--rl-border);
  color: var(--rl-text); font-size: 16px; text-decoration: none !important;
}
.rl-w-row:last-child { border-bottom: 0; }
.rl-w-row:active { background: var(--rl-accent-soft); }
.rl-w-row-main { flex: 1; min-width: 0; }
.rl-w-row-title { font-weight: 600; }
.rl-w-row-sub { font-size: 13.5px; color: var(--rl-text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rl-w-row i.bi-chevron-right { color: var(--rl-text-3); flex: none; }

/* Segmented toggle — works without JS (hidden radios + labels) */
.rl-w-seg {
  display: flex; border: 1px solid var(--rl-border-2); border-radius: 14px;
  overflow: hidden; background: var(--rl-surface);
}
.rl-w-seg label { flex: 1; position: relative; cursor: pointer; }
.rl-w-seg input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.rl-w-seg span {
  display: flex; align-items: center; justify-content: center;
  min-height: 56px; padding: 8px 6px;
  font-size: 16px; font-weight: 600; color: var(--rl-text-2);
  border-left: 1px solid var(--rl-border);
}
.rl-w-seg label:first-child span { border-left: 0; }
.rl-w-seg input:checked + span { background: var(--rl-accent); color: var(--rl-on-fill); }
.rl-w-seg input:focus-visible + span { box-shadow: inset 0 0 0 3px var(--rl-accent-soft); }
.rl-w-seg.danger-last label:last-child input:checked + span { background: var(--rl-danger); }

/* Stepper (− value +) */
.rl-w-stepper { display: flex; align-items: stretch; gap: 10px; }
.rl-w-step {
  flex: none; width: 72px; min-height: 64px;
  font: inherit; font-size: 30px; font-weight: 700; cursor: pointer;
  border: 1px solid var(--rl-border-2); border-radius: 14px;
  background: var(--rl-surface); color: var(--rl-text);
}
.rl-w-step:active { background: var(--rl-accent-soft); transform: scale(0.97); }
.rl-w-stepper .rl-w-num { flex: 1; min-width: 0; }

/* Big error + status */
.rl-w-error {
  background: var(--rl-danger-soft); color: var(--rl-danger);
  border: 2px solid var(--rl-danger); border-radius: 14px;
  font-size: 17px; font-weight: 600; padding: 14px 16px; margin: 0 0 16px;
}
.rl-w-pill { font-size: 14px; padding: 6px 14px; }
.rl-w-big { font-size: 44px; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.rl-w-meter { display: flex; align-items: baseline; gap: 10px; font-size: 16px; color: var(--rl-text-2); }
.rl-w-meter strong { font-size: 22px; color: var(--rl-text); font-variant-numeric: tabular-nums; }

.rl-w-back {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 48px; padding: 8px 4px; margin-bottom: 6px;
  font-size: 16px; font-weight: 600; color: var(--rl-text-2);
  text-decoration: none !important;
}
.rl-w-back:active { color: var(--rl-text); }

.rl-w-video {
  width: 100%; min-height: 260px; border-radius: 14px;
  background: #000; object-fit: cover; display: block;
}
.rl-w-textarea {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 17px;
  color: var(--rl-text); background: var(--rl-surface);
  border: 1px solid var(--rl-border-2); border-radius: 14px;
  padding: 14px 16px; outline: none;
}
.rl-w-textarea:focus { border-color: var(--rl-accent); box-shadow: 0 0 0 4px var(--rl-accent-soft); }
.rl-w-file { font-size: 15px; }
/* The camera button is a <label> wrapping a clipped file input, so the label
   cannot take focus itself — the ring has to come from the input inside it,
   or the control is invisible to a keyboard. */
.rl-w-filebtn:focus-within { outline: 2px solid var(--rl-accent); outline-offset: 2px; }

/* ── Work record — the description laid out as the crews wrote it.
   The substance of a work order, so it reads at body size, not as a footnote. */
.rl-rec { font-size: 14.5px; line-height: 1.6; color: var(--rl-text); }
.rl-rec-sect { padding: 11px 0; border-top: 1px solid var(--rl-border); }
.rl-rec-sect:first-child { border-top: 0; padding-top: 0; }
.rl-rec-lbl {
  font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
  color: var(--rl-text-3); font-weight: 600; margin: 0 0 6px;
}
.rl-rec p, .rl-rec li { max-width: 68ch; }
.rl-rec-kv { display: grid; grid-template-columns: 92px 1fr; gap: 7px 14px; align-items: baseline; }
.rl-rec-facts { display: flex; flex-wrap: wrap; gap: 8px; }
.rl-rec-fact {
  background: var(--rl-accent-soft); border: 1px solid var(--rl-border-2);
  border-radius: 6px; padding: 4px 9px; font-size: 12px; color: var(--rl-text-2);
}
.rl-rec-fact b { color: var(--rl-text); font-weight: 600; font-variant-numeric: tabular-nums; }
.rl-rec-steps { list-style: none; margin: 0; padding: 0; counter-reset: rl-step; }
.rl-rec-steps li { display: flex; gap: 11px; padding: 5px 0; }
.rl-rec-steps li::before {
  counter-increment: rl-step; content: counter(rl-step);
  flex: none; width: 19px; height: 19px; margin-top: 2px; border-radius: 50%;
  background: var(--rl-accent-soft); border: 1px solid var(--rl-border-2);
  color: var(--rl-accent); font-size: 10.5px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.rl-rec-badge {
  display: inline-block; font-size: 10.5px; padding: 3px 9px; border-radius: 20px;
  font-weight: 700; letter-spacing: .05em; background: var(--rl-accent-soft); color: var(--rl-text-2);
}
.rl-rec-fail { background: var(--rl-danger-soft); color: var(--rl-danger); }
.rl-rec-caution { background: var(--rl-warning-soft); color: var(--rl-warning); }
.rl-rec-src { font-size: 11px; color: var(--rl-text-3); margin: 10px 0 0; font-style: italic; }
/* Workshop screens are read at arm's length with gloves on. */
.rl-w .rl-rec { font-size: 16px; }
.rl-w .rl-rec-kv { grid-template-columns: 104px 1fr; }

/* ── Service certificate — one block per service, not one table row.
   A row could hold a truncated title and nothing else, which is why the
   narrative ended up in a tooltip that never printed. Colours come from the
   --rl-* tokens so the certificate's print block, which redefines the tokens
   rather than allow-listing components, recolours these for paper too. */
.rl-svc { padding: 18px 20px; }
.rl-svc + .rl-svc { border-top: 1px solid var(--rl-border); }
.rl-svc-head { margin-bottom: 12px; }
.rl-svc-grade { margin: 0 0 4px; font-size: 16px; font-weight: 700; color: var(--rl-text); }
.rl-svc-meta { font-size: 12.5px; color: var(--rl-text-2); line-height: 1.7; }
.rl-svc-title { margin: 0 0 12px; font-size: 14.5px; color: var(--rl-text); max-width: 68ch; }
.rl-svc-rec { margin: 0 0 12px; }
.rl-svc-lbl {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--rl-accent); font-weight: 700; margin: 0 0 6px;
}
.rl-svc-none { margin: 0 0 12px; font-size: 13.5px; color: var(--rl-text-3); font-style: italic; }
.rl-svc-basis { margin: 0; font-size: 11.5px; color: var(--rl-text-3); }

/* ── Reduced motion ──
   Not a blanket `animation: none` on everything: some of this motion is the
   only thing telling you the system heard you. Each case gets the outcome
   without the movement.

   Kept, deliberately:
   - the mic's level ring still SIZES with your voice, because "it isn't
     hearing me" is the question it exists to answer. Only the easing goes,
     so it steps rather than glides.
   - toasts and the offline banner still appear and disappear.
   Removed: timed pulses, slides, entrance fades and press-scaling. */
@media (prefers-reduced-motion: reduce) {
  .rl-collapse-chev,
  .rl-rail,
  .rl-scrim,
  .rl-btn { transition: none; }

  /* Press feedback becomes colour, not size. */
  .rl-btn:active,
  .rl-w-btn:active,
  .rl-w-step:active { transform: none; }
  .rl-btn:active,
  .rl-w-step:active { background: var(--rl-accent-soft); }

  /* The pulse only ever meant "recording". A steady ring says it without
     the 1.2s loop, and stays on for as long as the state does. */
  .rl-asst-mic.live { animation: none; box-shadow: 0 0 0 5px var(--rl-danger-soft); }
  .rl-asst-mic.live[style*="--rl-level"] { transition: none; }
}

/* ---- feedback panel ---- */
.rl-fb { position: fixed; right: 16px; bottom: 16px; z-index: 80;
  width: min(400px, calc(100vw - 32px));
  background: var(--rl-surface); border: 1px solid var(--rl-border);
  border-radius: var(--rl-radius-lg); box-shadow: 0 18px 50px rgba(0,0,0,.34);
  display: flex; flex-direction: column; overflow: hidden; }
.rl-fb[hidden] { display: none !important; }
.rl-fb-head { display: flex; align-items: center; gap: 8px;
  padding: 12px 14px; border-bottom: 1px solid var(--rl-border); }
.rl-fb-head strong { flex: 1; font-size: 14.5px; }
.rl-fb-form { padding: 14px; display: flex; flex-direction: column; gap: 10px; }
.rl-fb-kinds { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px; }
.rl-fb-kind { font-size: 12.5px; padding: 9px 6px; cursor: pointer;
  background: var(--rl-bg); color: var(--rl-text-2);
  border: 1px solid var(--rl-border); border-radius: var(--rl-radius); }
.rl-fb-kind.is-on { background: var(--rl-accent-soft); color: var(--rl-accent);
  border-color: var(--rl-accent); }
.rl-fb-say { position: relative; }
.rl-fb-say textarea { width: 100%; padding-right: 46px; }
.rl-fb-mic { position: absolute; right: 8px; bottom: 8px; width: 34px; height: 34px;
  border-radius: 999px; cursor: pointer; border: 1px solid var(--rl-border);
  background: var(--rl-bg); color: var(--rl-text-2); }
.rl-fb-mic.is-live { background: var(--rl-danger); color: #fff; border-color: var(--rl-danger); }
.rl-fb-photo { font-size: 13px; color: var(--rl-text-2); cursor: pointer; }
.rl-fb-photo input { display: block; margin-top: 4px; font-size: 12px; }
.rl-fb-prompt { margin-top: var(--rl-space-4); color: var(--rl-text-3); font-size: 14px; }
.rl-link { background: none; border: 0; padding: 0; margin: 0; font: inherit;
  color: var(--rl-accent); text-decoration: underline; cursor: pointer; }
.rl-link:focus-visible { outline: 2px solid var(--rl-accent); outline-offset: 2px; border-radius: 4px; }

/* ---- features board ---- */
.rl-fb-board { display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px; align-items: start; }
@media (max-width: 1100px) { .rl-fb-board { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .rl-fb-board { grid-template-columns: 1fr; } }
.rl-fb-col-head { font-size: 13px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--rl-text-3); margin: 0 0 10px; }
.rl-fb-col-head span { color: var(--rl-text-3); opacity: .7; }
.rl-fb-card { background: var(--rl-surface); border: 1px solid var(--rl-border);
  border-radius: 12px; padding: 14px; margin-bottom: 10px; }
.rl-fb-card h3 { font-size: 15px; margin: 0 0 6px; }
.rl-fb-card h3 a { color: var(--rl-text); text-decoration: none; }
.rl-fb-card h3 a:hover { color: var(--rl-accent); text-decoration: underline; }
.rl-fb-card p { font-size: 13.5px; color: var(--rl-text-2); margin: 0; }
.rl-fb-note { border-left: 2px solid var(--rl-accent); padding-left: 10px; margin-top: 8px !important; }
.rl-fb-by { margin-top: 8px !important; color: var(--rl-text-3) !important; font-size: 12.5px !important; }
.rl-fb-empty { color: var(--rl-text-3); font-size: 13px; }
.rl-fb-col.st-not_planned { opacity: .72; }
.rl-fb-move { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.rl-fb-move select, .rl-fb-move input { flex: 1 1 100%; font-size: 13px; }
.rl-fb-shot { max-width: min(560px, 100%); border-radius: 12px; }

/* A row whose data is usable but whose SOURCE needs a human fix — e.g. two Xero
   tracking options sharing one P-number. Deliberately quieter than a banner:
   the figure beside it is right, it is the upstream record that is wrong. */
.rl-flag {
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--rl-warning);
}

/* ---- Executive operations report ---------------------------------------
   Read top to bottom as a document, not scanned as a dashboard: sections get
   a rule and space rather than sitting in cards competing for attention. The
   issued Word report is the shape being matched, so its conventions carry
   over — a "basis" note under any table whose figure needs its method stated,
   and green/red on week-on-week movement. */
.rl-rep-section { margin-top: var(--rl-space-7); }
.rl-rep-section > h2 {
  font-size: 15px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--rl-text-2); border-bottom: 1px solid var(--rl-border);
  padding-bottom: var(--rl-space-2); margin: 0 0 var(--rl-space-3);
}
.rl-rep-section > h3 {
  font-size: 14px; margin: var(--rl-space-5) 0 var(--rl-space-2);
  color: var(--rl-text);
}
.rl-rep-lede { color: var(--rl-text-2); font-size: 13.5px; margin: 0 0 var(--rl-space-3); }
.rl-rep-lede strong { color: var(--rl-text); }

/* The "Availability basis:" / "Budget result:" footers the issued report puts
   under its tables. Not a caption — it states how the figure above was made,
   so it has to survive printing and stay readable at small sizes. */
.rl-rep-basis {
  margin-top: var(--rl-space-2); padding-left: var(--rl-space-3);
  border-left: 2px solid var(--rl-border-2);
  font-size: 12.5px; line-height: 1.5; color: var(--rl-text-2);
}

.rl-up { color: var(--rl-success); }
.rl-down { color: var(--rl-danger); }
.rl-num { font-variant-numeric: tabular-nums; }

/* Per-rig cards: the report devotes a block to each rig, two to a row. */
.rl-rep-cards {
  display: grid; gap: var(--rl-space-3);
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
.rl-rep-card {
  background: var(--rl-surface); border: 1px solid var(--rl-border);
  border-radius: var(--rl-radius-lg); padding: var(--rl-space-4);
}
.rl-rep-card h4 { margin: 0 0 2px; font-size: 14px; }
.rl-rep-card .rl-rep-proj { color: var(--rl-text-3); font-size: 12.5px; margin: 0 0 var(--rl-space-3); }
.rl-rep-card dl { display: grid; grid-template-columns: 1fr 1fr; gap: var(--rl-space-2); margin: 0; }
.rl-rep-card dt { font-size: 11.5px; color: var(--rl-text-3); text-transform: uppercase; letter-spacing: .04em; }
.rl-rep-card dd { margin: 0 0 var(--rl-space-2); font-size: 14px; font-variant-numeric: tabular-nums; }

.rl-commentary { font-size: 13.5px; line-height: 1.6; margin: 0 0 var(--rl-space-2); }
.rl-evidence {
  margin: 0 0 var(--rl-space-3) var(--rl-space-3); padding-left: var(--rl-space-3);
  border-left: 2px solid var(--rl-accent-soft);
  font-size: 12.5px; color: var(--rl-text-2);
}

/* A section the issued report carries that Riglog has no source for. It is
   printed, not dropped: a reader who knows the document would otherwise not
   know whether it was forgotten or withheld. */
.rl-rep-unsourced {
  border: 1px dashed var(--rl-border-2); border-radius: var(--rl-radius);
  padding: var(--rl-space-3); color: var(--rl-text-2); font-size: 13px;
}

@media print {
  .rl-rep-section { break-inside: avoid-page; }
  .rl-rep-card { break-inside: avoid; }
  .rl-page-actions, form { display: none !important; }
}

/* Expandable rig detail on the operations report. The row is a real table row
   so the disclosure sits under the rig it belongs to; the summary is styled
   quiet because eight of them stacked must not compete with the figures. */
.rl-rep-expand-row > td { padding: 0 !important; border-top: 0 !important; }
.rl-rep-expand > summary {
  cursor: pointer; padding: 4px 8px; font-size: 12px;
  color: var(--rl-text-3); list-style-position: inside;
}
.rl-rep-expand > summary:hover { color: var(--rl-accent); }
.rl-rep-expand[open] > summary { color: var(--rl-text-2); }
.rl-rep-expand-body {
  padding: var(--rl-space-3); margin: 0 0 var(--rl-space-2);
  background: var(--rl-surface); border: 1px solid var(--rl-border);
  border-radius: var(--rl-radius);
}
.rl-rep-expand-body dl {
  display: grid; gap: var(--rl-space-2) var(--rl-space-4); margin: 0 0 var(--rl-space-3);
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}
.rl-rep-expand-body dt {
  font-size: 11px; color: var(--rl-text-3);
  text-transform: uppercase; letter-spacing: .04em;
}
.rl-rep-expand-body dd { margin: 0; font-size: 13.5px; font-variant-numeric: tabular-nums; }

@media print {
  /* A closed <details> prints as its summary only, which would drop every
     rig's detail from a printed board pack. */
  .rl-rep-expand > summary { display: none; }
  .rl-rep-expand-body { display: block !important; }
}
