/* Shared styles - mobile-first, since entry speed on a phone is the adoption risk
   (see docs/CLAUDE.md Gotchas). Large touch targets, minimal chrome. */

/* Dark only, deliberately. A light theme was considered and dropped (YC, Q3
   2026-08-06) - one theme means one set of colours to keep legible, rather than
   two. `color-scheme: dark` is the important line: it tells the browser to draw
   its OWN controls (the date picker's calendar icon, the time picker's clock)
   in dark styling. Without it those icons render black-on-black and effectively
   disappear. */
:root {
  color-scheme: dark;

  --color-bg: #16171a;
  --color-surface: #212226;
  --color-border: #34363b;
  --color-text: #e8e9eb;
  --color-text-muted: #9a9fa8;
  --color-primary: #e0935a;
  --color-primary-hover: #eaa876;
  --color-error: #e57368;
  --color-error-bg: #3a2321;
  --color-brand: #f9b352;
  --radius: 10px;
  --spacing: 16px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--color-bg);
  color: var(--color-text);
  min-height: 100vh;
}

.page-center {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: var(--spacing);
}

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 28px 24px;
  width: 100%;
  max-width: 380px;
}

.card h1 {
  font-size: 20px;
  margin: 0 0 4px;
}

.card .subtitle {
  color: var(--color-text-muted);
  font-size: 14px;
  margin: 0 0 24px;
}

.field {
  margin-bottom: 16px;
}

.field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 6px;
  color: var(--color-text-muted);
}

/* A checkbox is the one input that must NOT be full width - the rule below would
   stretch it across the row, which is what pushed the box away from its wording
   and left it floating at the far end. Box first, then the sentence, on one line.
   Sized well above the browser default (~13px) so it's easy to hit with a thumb,
   and the row keeps a 44px touch target. */
.field label.checkbox-label {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin-bottom: 2px;
  font-size: 14px;
  font-weight: 500;
  color: var(--color-text);
  cursor: pointer;
}

.field label.checkbox-label input[type="checkbox"] {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
  accent-color: var(--color-primary);
  cursor: pointer;
}

.field input {
  width: 100%;
  padding: 14px;
  font-size: 16px; /* 16px minimum avoids iOS zoom-on-focus */
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
}

.field input:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

button.primary {
  width: 100%;
  padding: 14px;
  font-size: 16px;
  font-weight: 600;
  color: #fff;
  background: var(--color-primary);
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  min-height: 48px; /* touch target */
}

button.primary:hover {
  background: var(--color-primary-hover);
}

button.primary:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.error-message {
  display: none;
  background: var(--color-error-bg);
  color: var(--color-error);
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 14px;
  margin-bottom: 16px;
}

.error-message.visible {
  display: block;
}

.help-text {
  text-align: center;
  font-size: 13px;
  color: var(--color-text-muted);
  margin-top: 20px;
}

/* --- App shell (claims.html) --- */

.app-header {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  padding: 14px var(--spacing);
}

.app-header .employee-info {
  font-size: 14px;
}

.app-header .employee-info strong {
  display: block;
  font-size: 15px;
}

.app-header .employee-info span {
  color: var(--color-text-muted);
}

.icon-button {
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 8px 14px;
  font-size: 13px;
  color: var(--color-text);
  cursor: pointer;
}

.app-main {
  max-width: 560px;
  margin: 0 auto;
  padding: var(--spacing) var(--spacing) 96px;
}

.section-title {
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
  margin: 24px 0 10px;
}

.section-title:first-child {
  margin-top: 0;
}

/* --- Form controls beyond the login page's text/password inputs --- */

.field select,
.field textarea {
  width: 100%;
  padding: 14px;
  font-size: 16px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
  font-family: inherit;
}

/* Dropdowns run slightly smaller than the 16px text inputs so long option names
   (e.g. "Motor Vehicle Misc Expenses (3rd party transport eg Grab/Lalamove)")
   fit further before the browser truncates them. Safe to go below 16px here:
   iOS only zooms on focus for typed inputs, and a <select> opens a native
   picker instead. Native dropdowns cannot wrap text in any browser, so this
   plus full width is as far as CSS can take it. */
.field select {
  font-size: 15px;
}

.field textarea {
  resize: vertical;
  min-height: 60px;
}

.field-row {
  display: flex;
  gap: 12px;
}

.field-row .field {
  flex: 1;
  min-width: 0; /* lets a flex child shrink instead of forcing overflow */
}

/* On a phone, side-by-side fields leave each one about half the screen, which is
   what was cutting off "Select a department". Stack them so each gets the full
   width. */
@media (max-width: 520px) {
  .field-row {
    flex-direction: column;
    gap: 0;
  }
}

/* Marks a mandatory field. Every descriptive field a category shows is
   mandatory (YC, Q7) - a claim with no description is useless to an approver. */
.required-mark {
  color: var(--color-primary);
  margin-left: 2px;
  font-weight: 700;
}

.conditional-field {
  display: none;
}

.conditional-field.visible {
  display: block;
}

.hint {
  font-size: 12px;
  color: var(--color-text-muted);
  margin-top: 4px;
}

.cap-warning {
  font-size: 12px;
  color: var(--color-error);
  margin-top: 4px;
}

/* --- Duplicate / info banners, distinct from the login page's hard error --- */

.warning-banner {
  display: none;
  background: var(--color-error-bg);
  color: var(--color-error);
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 14px;
  margin-bottom: 16px;
}

.warning-banner.visible {
  display: block;
}

.warning-banner button {
  margin-top: 8px;
  background: none;
  border: 1px solid currentColor;
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 13px;
  color: inherit;
  cursor: pointer;
}

/* --- Claim list --- */

.claim-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.claim-item {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 14px;
}

.claim-item .row-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
}

.claim-item .category-name {
  font-weight: 600;
  font-size: 15px;
}

.claim-item .amount {
  font-weight: 700;
  font-size: 15px;
  white-space: nowrap;
}

.claim-item .meta {
  color: var(--color-text-muted);
  font-size: 13px;
  margin-top: 4px;
}

.claim-item .actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.claim-item .actions button {
  flex: 1;
  padding: 8px;
  font-size: 13px;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
}

.claim-item .actions button.delete {
  color: var(--color-error);
  border-color: var(--color-error);
}

.status-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 3px 8px;
  border-radius: 20px;
  background: var(--color-bg);
  color: var(--color-text-muted);
  margin-top: 4px;
}

.status-badge.status-draft {
  background: var(--color-error-bg);
  color: var(--color-primary);
}

.empty-state {
  text-align: center;
  color: var(--color-text-muted);
  font-size: 14px;
  padding: 24px;
}

/* --- Sticky submit bar --- */

.submit-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding: 12px var(--spacing);
  display: flex;
  align-items: center;
  gap: 12px;
}

.submit-bar .draft-total {
  flex: 1;
  font-size: 13px;
  color: var(--color-text-muted);
}

.submit-bar .draft-total strong {
  display: block;
  font-size: 16px;
  color: var(--color-text);
}

.submit-bar button.primary {
  width: auto;
  padding: 12px 20px;
}

/* --- Branding ---
   Files are supplied by YC into web/img/. If they're missing these rules simply
   render nothing - no broken-image icons, no layout shift. */

.brand-logo {
  display: block;
  max-width: 220px;
  width: 70%;
  margin: 0 auto 20px;
}

/* Turnstile renders a fixed-width iframe, which sits left-aligned in its
   container and so drifts off-centre differently on each screen width.
   Centring the container fixes it everywhere. */
.cf-turnstile {
  display: flex;
  justify-content: center;
  margin-bottom: 16px;
}

/* Faded mark behind the app pages. Fixed so it stays put while the page
   scrolls, and pointer-events:none so it can never intercept a tap. */
.app-watermark {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url("../img/logo-mark.svg");
  background-repeat: no-repeat;
  background-position: center 45%;
  background-size: min(78vw, 520px);
  /* Raised from 0.05 at YC's request. Deliberately NOT the 0.8 he suggested -
     at that strength the form text becomes unreadable over it. This is roughly
     four times more visible than before; easy to push further if he wants. */
  opacity: 0.2;
}

/* Lifts real content above the watermark, which sits at z-index 0. */
.app-header,
.app-main {
  position: relative;
  z-index: 1;
}

/* The submit bar needs the same lift but must stay FIXED - it was previously
   grouped with the rule above, which reset it to position:relative and quietly
   dropped it to the bottom of the page. The giveaway that fixed was intended:
   it still carries bottom/left/right:0 (meaningless when relative), and
   .app-main reserves 96px of bottom padding purely to clear it. */
.submit-bar {
  z-index: 1;
}

/* --- Cut-off notice, shown once per login --- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--spacing);
  background: rgba(0, 0, 0, 0.6);
}

.modal-backdrop.visible {
  display: flex;
}

.modal {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 24px;
  max-width: 400px;
  width: 100%;
}

.modal h2 {
  font-size: 17px;
  margin: 0 0 14px;
}

.modal .deadline-line {
  font-size: 15px;
  margin: 0 0 6px;
}

.modal .deadline-line strong {
  color: var(--color-primary);
}

.modal .modal-note {
  font-size: 13px;
  color: var(--color-text-muted);
  margin: 14px 0 20px;
}

/* --- Inactivity warning --- */

.session-warning {
  position: fixed;
  left: var(--spacing);
  right: var(--spacing);
  bottom: 84px;
  z-index: 60;
  display: none;
  align-items: center;
  gap: 12px;
  background: var(--color-error-bg);
  color: var(--color-error);
  border: 1px solid var(--color-error);
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 14px;
}

.session-warning.visible {
  display: flex;
}

.session-warning span {
  flex: 1;
}

.session-warning button {
  background: var(--color-error);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

/* --- Filter + search over the claim list --- */

/* Wraps rather than crushes. Three controls don't fit one phone-width row, and
   without wrapping the search box is the one that collapses - it's the only
   flexible item, so it absorbs all the shortfall. */
.list-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.list-controls input,
.list-controls select {
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  font-family: inherit;
}

/* Sized separately, and 16px on the typed input is deliberate rather than a
   style choice: iOS auto-zooms the page whenever you focus a text field smaller
   than 16px. That zoom is what forced `maximum-scale=1` into the viewport tag,
   which in turn disabled pinch-to-zoom for everybody. Sizing the input properly
   removes the need for the constraint.
   The select can stay smaller - selects open a native picker and never trigger
   the zoom. */
.list-controls input {
  font-size: 16px;
}

.list-controls select {
  font-size: 14px;
}

/* A real minimum, not 0 - below about 150px a search box is unusable, so it
   should push a sibling onto the next row instead of shrinking away. */
.list-controls input {
  flex: 1 1 160px;
  min-width: 150px;
}

.list-controls select {
  flex: 0 1 auto;
  max-width: 45%;
}

/* width:auto is doing real work here - .secondary-button is width:100% by default
   (it's a full-width button everywhere else), which would claim a whole row even
   on a wide screen. Sized to its label instead, and never shrinks below it. */
.list-controls .secondary-button {
  width: auto;
  flex: 0 0 auto;
  white-space: nowrap;
  padding: 10px 14px;
  font-size: 14px;
}

/* --- Claims grouped by claim period --- */

.period-group + .period-group {
  margin-top: 18px;
}

.period-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  padding: 0 2px 6px;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 10px;
}

.period-header .period-name {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.period-header .period-total {
  font-size: 13px;
  font-weight: 700;
  color: var(--color-text);
  white-space: nowrap;
}

/* --- Pilot tester feedback page --- */

.feedback-main {
  padding-bottom: 48px;
}

.feedback-title {
  font-size: 20px;
  line-height: 1.35;
  margin: 8px 0 16px;
}

.intro-card p {
  margin: 0 0 12px;
  font-size: 15px;
  line-height: 1.5;
}

.intro-card p:last-child {
  margin-bottom: 0;
}

/* ---- The entry form's own panel ------------------------------------------
   Every card shared one surface colour, so the page read as a single uniform
   stack and the form you actually type into looked no different from the claims
   listed under it. This lifts it out.

   Lighter and slightly cooler than --color-surface, which reads as "raised"
   rather than "highlighted". Deliberately NOT tinted gold: the Save button is
   the only gold element on this form, and that is exactly what makes it read as
   the action - a gold panel behind it would flatten that. The warm accent shows
   up only in the border, which ties the panel to the brand without competing. */
.entry-card {
  background: #262931;
  border-color: rgba(224, 147, 90, 0.28);
}

/* ---- Back to top ---------------------------------------------------------
   Bottom-right, clear of the fixed submit bar (which is roughly 70px tall, so
   88px keeps a comfortable gap). Hidden until the page is actually scrolled -
   an arrow sitting there on a two-line list is just clutter. */

.to-top {
  position: fixed;
  right: var(--spacing);
  bottom: 88px;
  z-index: 40;
  width: 44px;
  height: 44px; /* full touch target */
  padding: 0;
  display: none;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
}

.to-top.visible {
  display: flex;
}

.to-top svg {
  width: 20px;
  height: 20px;
}

.to-top:hover {
  color: var(--color-primary);
  border-color: var(--color-primary);
}

/* ---- Print reminder ------------------------------------------------------
   Green is used here and nowhere else in the app, which is the point: it reads
   as "environment" instantly without needing to be explained. Outline rather
   than filled keeps it consistent with the app's light-touch styling. */

.eco-modal {
  text-align: center;
}

/* Character counter under the remark box. */
.char-count {
  text-align: right;
  margin-top: 4px;
}

.char-count-low {
  color: var(--color-primary);
}

/* Grows on each open: the whole mark scales up from its base while the outline
   draws itself - trunk, then canopy, then branches. Roughly 1.7s end to end.
   Going display:none -> flex restarts CSS animations, so it replays every time
   the modal opens rather than only the first time. */
.eco-tree {
  width: 56px;
  height: 56px;
  color: #7bc96f;
  margin: 0 auto 4px;
  display: block;
  transform-origin: 50% 100%; /* grows from the ground, not the middle */
  animation: eco-grow 1.7s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes eco-grow {
  0%   { transform: scale(0.55); opacity: 0; }
  30%  { opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* stroke-dasharray works on a 0-1 scale thanks to pathLength="1" in the markup. */
.eco-tree path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: eco-draw 0.6s ease forwards;
}

/* Scoped under .eco-tree deliberately: `.eco-tree path` above is more specific
   than a bare `.eco-trunk`, and its `animation:` shorthand would reset these
   delays back to 0 - which silently killed the stagger the first time. */
.eco-tree .eco-trunk    { animation-delay: 0.05s; }
.eco-tree .eco-canopy   { animation-delay: 0.35s; animation-duration: 1s; }
.eco-tree .eco-branches { animation-delay: 1.15s; }

@keyframes eco-draw {
  to { stroke-dashoffset: 0; }
}

/* ---- Warning mark (Phase 3: the "approve ALL" confirmation) --------------
   Not yet reachable in the app - the approver screens don't exist. Built now so
   it's ready, and so the shape matches the eco modal it sits alongside.
   Bounces once rather than repeating: a mark that keeps moving reads as an
   alarm, and this is a pause-and-think, not an emergency. */

/* Draws its own ring around a plain "!" character. Originally sized for an SVG,
   which left the mark rendering as a bare red exclamation with no circle. Doing
   it in CSS means no extra asset to load or keep in step with the theme. */
.warn-mark {
  width: 56px;
  height: 56px;
  margin: 0 auto 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 3px solid #e5534b;
  border-radius: 50%;
  color: #e5534b;
  font-size: 30px;
  font-weight: 700;
  line-height: 1;
  animation: warn-bounce 0.9s cubic-bezier(0.28, 0.84, 0.42, 1) both;
}

@keyframes warn-bounce {
  0%   { transform: scale(0.4) translateY(-14px); opacity: 0; }
  45%  { transform: scale(1.12) translateY(0);    opacity: 1; }
  65%  { transform: scale(0.94) translateY(-5px); }
  82%  { transform: scale(1.03) translateY(0); }
  100% { transform: scale(1)    translateY(0);    opacity: 1; }
}

.eco-actions {
  display: flex;
  gap: 10px;
  margin-top: 18px;
}

.eco-actions button {
  flex: 1;
  width: auto;
  margin: 0;
}

/* ---- "The system is working" feedback ------------------------------------
   Every backend call is a Power Automate HTTP flow, which takes 1-4 seconds.
   That pause is unavoidable, so the job is to make it obvious the tap landed -
   testers reported not knowing whether they'd actually pressed anything.

   Two levels, deliberately different in weight:
     - Buttons get an inline spinner. Saving happens up to ~50 times a month, so
       it must stay lightweight and not take over the screen.
     - Submitting gets a full overlay with the company mark. It is rare, slow
       (two round trips), and irreversible - worth blocking the screen for, and
       it also makes double-submission impossible. */

.button-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 8px;
  vertical-align: -2px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

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

.busy-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(2px);
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 16px;
  text-align: center;
  padding: 24px;
}

.busy-overlay.visible {
  display: flex;
}

.busy-logo {
  width: 84px;
  height: 84px;
  background: url("../img/logo-mark.svg") center / contain no-repeat;
  animation: busy-pulse 1.4s ease-in-out infinite;
}

/* A pulse rather than a spin - a rotating logo reads as broken, a breathing one
   reads as working. */
@keyframes busy-pulse {
  0%, 100% { transform: scale(0.9); opacity: 0.55; }
  50%      { transform: scale(1.05); opacity: 1; }
}

.busy-message {
  font-size: 15px;
  color: var(--color-text);
}

.busy-sub {
  font-size: 13px;
  color: var(--color-text-muted);
}

/* Respect the system setting - animation can trigger nausea for some people.
   Hold the mark steady and let the wording carry the message instead. */
@media (prefers-reduced-motion: reduce) {
  .button-spinner { animation: none; }
  .busy-logo { animation: none; opacity: 1; }

  /* Show the finished tree and warning mark rather than animating in - and note
     the paths must be un-dashed explicitly, or an undrawn outline stays
     invisible forever. */
  .eco-tree,
  .warn-mark { animation: none; opacity: 1; transform: none; }
  .eco-tree path { animation: none; stroke-dashoffset: 0; }
}

/* ---- Print / Save-as-PDF -------------------------------------------------
   Chosen over a CSV download: works identically on phone and desktop, needs no
   file handling, and on a phone the browser's print dialog offers "Save as PDF"
   - which is how most staff will actually keep a copy.

   The print header is hidden on screen and only appears on paper, because the
   on-screen header carries a Log out button that must not print. */
.print-header,
.print-table {
  display: none;
}

/* Staff IDs are uppercase everywhere. This only changes what is DRAWN - the
   value is uppercased in login.js as well, because text-transform does not touch
   what gets submitted. Both are needed; neither alone is enough. */
#staff-id {
  text-transform: uppercase;
}

/* Why a claim was returned or rejected, on the claimant's own card. Without it
   the claimant sees RETURNED and has to go and ask someone what to fix. */
.action-note {
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: var(--radius);
  border-left: 3px solid var(--color-primary);
  background: rgba(255, 255, 255, 0.04);
  font-size: 13px;
  line-height: 1.45;
}

.action-note strong {
  display: block;
  margin-bottom: 2px;
}

/* Rejected is terminal - red, because nothing the claimant does will change it. */
.action-note.rejected {
  border-left-color: var(--color-error);
  color: var(--color-error);
}

.action-note.rejected span {
  color: var(--color-text);
}

/* --- Help page ------------------------------------------------------------ */

.faq-item {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 12px;
}

.faq-item h3 {
  margin: 0 0 10px;
  font-size: 16px;
}

.faq-item p {
  margin: 0 0 10px;
  font-size: 15px;
  line-height: 1.55; /* generous - a lot of readers are on a phone in a hurry */
}

.faq-item p:last-child {
  margin-bottom: 0;
}

.faq-warn {
  border-left: 3px solid var(--color-error);
  padding-left: 10px;
}

/* Inline label matching the badges on a real claim, so the words in Help look
   like the words on screen. */
.faq-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.08);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.3px;
}

.faq-status {
  margin: 0;
}

.faq-status dt {
  margin-top: 12px;
}

.faq-status dt:first-child {
  margin-top: 0;
}

.faq-status dd {
  margin: 4px 0 0;
  font-size: 15px;
  line-height: 1.5;
}

/* The deadline picture. Scales with the card; text sizes are set here rather
   than on the SVG so they follow the page. */
.faq-timeline {
  display: block;
  width: 100%;
  height: auto;
  margin: 14px 0 16px;
  color: var(--color-text);
}

.faq-tl-date {
  font-size: 9px;
  font-weight: 600;
  fill: var(--color-text);
  text-anchor: middle;
}

.faq-tl-top {
  font-size: 8px;
  fill: var(--color-text-muted);
  text-anchor: middle;
}

.faq-tl-note {
  font-size: 8px;
  fill: var(--color-error);
  text-anchor: middle;
}

.faq-tl-legend {
  font-size: 9px;
  fill: var(--color-text-muted);
  text-anchor: middle;
}

/* --- Approver mode -------------------------------------------------------- */
/*
   Approving someone else's money is a different job from claiming your own, and
   the two screens otherwise look identical. So approver mode restains the whole
   page: the watermark and every primary button turn soft pink. It reads at a
   glance, from across a room, before any label is read (YC 2026-08-13).

   Done by overriding the two primary tokens rather than restyling buttons, so
   anything added later inherits it for free. Pink is matched to the orange's
   lightness so the two modes feel like one product in two states.
*/
body.approver-mode {
  --color-primary: #cf7f96;
  --color-primary-hover: #dd93a8;
}

/* The mark is a background IMAGE, which cannot be recoloured. Re-drawing it as a
   MASK lets the pink come from background-color instead. Position and size must
   mirror .app-watermark exactly or the mark shifts when switching modes. */
body.approver-mode .app-watermark {
  background-image: none;
  background-color: var(--color-primary);
  -webkit-mask-image: url("../img/logo-mark.svg");
  mask-image: url("../img/logo-mark.svg");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center 45%;
  mask-position: center 45%;
  -webkit-mask-size: min(78vw, 520px);
  mask-size: min(78vw, 520px);
}

/* --- Approver screens ------------------------------------------------------ */

.select-all-row {
  margin: 4px 0 12px;
}

.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.action-row .primary {
  flex: 1 1 100%;
}

.action-row .secondary-button {
  flex: 1;
  min-height: 48px;
}

/* Reject is terminal - the claimant cannot resubmit. It should not look like a
   neighbour of Return. */
.secondary-button.danger {
  color: var(--color-error);
  border-color: var(--color-error);
}

.line-row {
  position: relative;
  padding-left: 44px; /* room for the checkbox */
}

.line-pick {
  position: absolute;
  top: 14px;
  left: 12px;
  margin: 0;
}

/* Every approver sees a claim from the moment it is submitted, but only the one
   whose turn it is can act. The rest are greyed and labelled with what they are
   waiting on - visibility without the ability to jump the queue. */
.line-row.not-mine {
  opacity: 0.55;
}

.waiting-on {
  font-style: italic;
}

/* The whole claimant row is one big button - an Open button per row was
   unusable once an approver has 20-30 people waiting. A real <button> so it
   works by keyboard and is announced as pressable. */
.claimant-row {
  display: block;
  width: 100%;
  position: relative;
  padding-right: 34px; /* room for the chevron */
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.claimant-row:hover {
  border-color: var(--color-primary);
}

.row-chevron {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  font-size: 22px;
  line-height: 1;
  color: var(--color-text-muted);
}

.modal-actions {
  display: flex;
  gap: 8px;
  margin-top: 16px;
}

.modal-actions button {
  flex: 1;
  min-height: 48px;
}

/* Present to screen readers, invisible on screen. Used for the per-line
   checkbox label, which would otherwise be an unlabelled control. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Navigation drawer ----------------------------------------------------- */

/* The browser's own [hidden] rule loses to ANY author rule that sets display -
   author styles beat the user-agent stylesheet whatever the specificity. That
   silently exposed "My approvals" to every non-approver, because .drawer-item
   sets display:flex. This puts hidden back in charge everywhere. */
[hidden] {
  display: none !important;
}

.menu-button {
  background: none;
  border: none;
  padding: 8px;
  margin-right: 4px;
  cursor: pointer;
  color: var(--color-text);
  line-height: 0;
  min-width: 44px;
  min-height: 44px;
}

.app-header .header-left {
  display: flex;
  align-items: center;
  gap: 4px;
}

.drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.drawer-backdrop.open {
  opacity: 1;
  pointer-events: auto;
}

.drawer {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  z-index: 50;
  width: min(78vw, 280px);
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  transform: translateX(-100%);
  transition: transform 0.22s ease;
  display: flex;
  flex-direction: column;
  padding: var(--spacing) 0;
}

.drawer.open {
  transform: translateX(0);
}

/* Someone who prefers less motion still needs the drawer to work - it just
   appears instead of sliding. */
@media (prefers-reduced-motion: reduce) {
  .drawer,
  .drawer-backdrop {
    transition: none;
  }
}

.drawer-header {
  padding: 0 var(--spacing) var(--spacing);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 8px;
}

.drawer-header strong {
  display: block;
  font-size: 15px;
}

.drawer-header span {
  font-size: 13px;
  color: var(--color-text-muted);
}

.drawer-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px var(--spacing);
  background: none;
  border: none;
  font-size: 15px;
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
  text-decoration: none;
  min-height: 48px;
}

.drawer-item:hover {
  background: rgba(255, 255, 255, 0.04);
}

.drawer-item.current {
  color: var(--color-primary);
  font-weight: 600;
  box-shadow: inset 3px 0 0 var(--color-primary);
}

/* Help and Log out are the two "leaving here" items, so they sit together at
   the foot of the drawer (YC 2026-08-17). Help takes the auto margin that
   pushes the pair down; Log out then follows it, separated by a rule - it is
   the one item you never want tapped by accident on the way to something else. */
.drawer-item.help {
  margin-top: auto;
  border-top: 1px solid var(--color-border);
}

.drawer-item.logout {
  color: var(--color-text-muted);
}

.drawer-badge {
  margin-left: auto;
  min-width: 22px;
  padding: 2px 7px;
  border-radius: 11px;
  background: var(--color-primary);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  text-align: center;
}

/* --- Paging --------------------------------------------------------------- */

.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 16px 0 8px;
}

.pager-status {
  flex: 1 1 100%;
  font-size: 0.85rem;
  opacity: 0.75;
}

.pager-buttons {
  display: flex;
  gap: 8px;
}

/* Comfortably thumb-sized - this is the control most used on a phone. */
.pager-buttons button {
  min-width: 96px;
  min-height: 44px;
}

.pager-buttons button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.pager-size {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  font-size: 0.85rem;
  opacity: 0.75;
}

/* 16px stops iOS zooming the page when the select is tapped. */
.pager-size select {
  width: auto;
  min-height: 44px;
  font-size: 16px;
}

.period-partial {
  margin-left: 8px;
  font-size: 0.75rem;
  font-weight: 400;
  opacity: 0.6;
}

@media (max-width: 480px) {
  /* Stacked, with the buttons full width and side by side. */
  .pager-buttons {
    flex: 1 1 100%;
  }

  .pager-buttons button {
    flex: 1;
  }

  .pager-size {
    flex: 1 1 100%;
    margin-left: 0;
    justify-content: flex-end;
  }
}

@media print {
  /* The app is dark-only. Printing that as-is would flood the page with ink and
     read poorly, so force plain black-on-white for everything. */
  *,
  *::before,
  *::after {
    background: #fff !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }

  /* Portrait deliberately. `size: landscape` was tried and removed: Android
     Chrome ignores it, so phones printed portrait while desktops printed
     landscape - the same claim looking different depending on the device. The
     table is sized to fit portrait instead. */
  @page {
    margin: 10mm;
  }

  /* The blank second page came from here. `min-height: 100vh` on body means
     "at least one full page" when printing, so even a short list pushed a
     trailing empty sheet out of the printer. */
  html,
  body {
    min-height: 0 !important;
    height: auto !important;
    margin: 0 !important;
    padding: 0 !important;
  }

  /* Anything interactive or decorative has no business on paper. */
  .app-watermark,
  .app-header,
  .modal-backdrop,
  .session-warning,
  .submit-bar,
  .list-controls,
  .error-message,
  .warning-banner,
  .no-print,
  .to-top,
  .pager,
  .period-partial,
  .edit-button,
  .delete-button {
    display: none !important;
  }

  body {
    font-size: 11pt;
  }

  /* The 96px bottom padding exists to clear the fixed submit bar on screen.
     That bar is hidden on paper, so the padding is just dead space that can
     spill onto another page. */
  .app-main {
    padding: 0 !important;
    margin: 0 !important;
    max-width: none;
  }

  /* Nothing after the table, so no trailing margin to push a page break. */
  .print-table {
    margin: 0 0 0 0;
  }

  main > *:last-child {
    margin-bottom: 0 !important;
  }

  .print-header {
    display: block;
    border-bottom: 2px solid #000;
    padding-bottom: 8px;
    margin-bottom: 14px;
  }

  .print-title {
    font-size: 16pt;
    font-weight: 700;
  }

  .print-meta {
    display: flex;
    justify-content: space-between;
    font-size: 10pt;
    margin-top: 4px;
  }

  /* Paper gets the data table, not the on-screen cards - a printout is for
     reading rows and columns, not for looking like the app. */
  .claim-list {
    display: none !important;
  }

  .print-table {
    display: table;
    width: 100%;
    border-collapse: collapse;
    /* 8pt keeps eight columns inside portrait A4 without the browser shrinking
       the whole page to fit, which is what makes printouts unreadable. */
    font-size: 8pt;
    table-layout: fixed;
  }

  .print-table th,
  .print-table td {
    border: 1px solid #666;
    padding: 2px 4px;
    text-align: left;
    vertical-align: top;
    /* Long merchant names and detail strings wrap instead of forcing the table
       wider than the page. */
    overflow-wrap: anywhere;
  }

  /* Give the space to the columns that actually carry variable-length text.
     Status has no column of its own - rows are grouped under a status heading
     instead, which frees the width for Category and Details. */
  .print-table th:nth-child(1) { width: 4%; }   /* No          */
  .print-table th:nth-child(2) { width: 10%; }  /* Date        */
  .print-table th:nth-child(3) { width: 13%; }  /* Reference   */
  .print-table th:nth-child(4) { width: 16%; }  /* Category    */
  .print-table th:nth-child(5) { width: 17%; }  /* Description */
  .print-table th:nth-child(6) { width: 19%; }  /* Details     */
  .print-table th:nth-child(7) { width: 9%; }   /* Department  */
  /* Wider than it looks necessary: "RM999,999.99" must never wrap or clip,
     and .num is nowrap so it would overflow rather than break. */
  .print-table th:nth-child(8) { width: 12%; }  /* Amount      */

  .print-table thead th {
    border-bottom: 2px solid #000;
    font-weight: 700;
    background: #eee !important;
  }

  /* Repeat the column headings at the top of each printed page. */
  .print-table thead {
    display: table-header-group;
  }

  .print-table tr {
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .print-table .num {
    text-align: right;
    white-space: nowrap;
  }

  /* Three visual levels so the hierarchy is obvious at a glance:
     MONTH heading (darkest) > status heading > rows > status subtotal, and each
     month closes with a grand total before the next begins. */

  .print-table .period-row th {
    background: #bbb !important;
    font-size: 11pt;
    padding: 8px 5px 6px;
    border-top: 2px solid #000;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    /* A heading stranded at the foot of a page reads like an error. */
    break-after: avoid;
    page-break-after: avoid;
  }

  .print-table .group-row th {
    background: #e2e2e2 !important;
    font-size: 9pt;
    padding-top: 6px;
    break-after: avoid;
    page-break-after: avoid;
  }

  .print-table .total-row td {
    font-weight: 700;
    border-top: 1px solid #000;
  }

  .print-table .grand-total-row td {
    font-weight: 700;
    font-size: 9pt;
    background: #e2e2e2 !important;
    border-top: 2px solid #000;
    border-bottom: 2px solid #000;
    padding: 5px;
  }

  .card {
    border: 0;
    padding: 0;
  }

  .section-title {
    font-size: 12pt;
    margin: 0 0 6px;
  }
}

/* One tap swaps the whole page between English, Malay and Chinese. Stacking all
   three under each other was tried first and dropped - it made the form roughly
   three times longer, and length is where people abandon a survey. */
.lang-switch {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-bottom: 18px;
}

.lang-button {
  flex: 1;
  padding: 9px 8px;
  font-size: 13px;
  font-family: inherit;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text-muted);
  cursor: pointer;
  min-height: 40px;
}

.lang-button.active {
  border-color: var(--color-primary);
  color: var(--color-primary);
  font-weight: 600;
}

/* Deadline needs to be the thing they can't miss on the intro - a request with
   no date on it gets done last. */
.deadline-banner {
  background: var(--color-error-bg);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 15px !important;
  text-align: center;
}

.deadline-banner strong {
  color: var(--color-primary);
}

.deadline-reminder {
  font-size: 13px;
  font-weight: 600;
  color: var(--color-primary);
  margin: -8px 0 16px;
}

.intro-warning {
  color: var(--color-text-muted);
  font-size: 14px !important;
  border-left: 3px solid var(--color-primary);
  padding-left: 12px;
}

/* Part chooser */
.set-picker {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.set-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  padding: 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
  min-height: 48px;
}

.set-card:hover {
  border-color: var(--color-primary);
}

.set-card-number {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-primary);
}

.set-card-title {
  font-size: 16px;
  font-weight: 600;
}

.set-card-meta {
  font-size: 13px;
  color: var(--color-text-muted);
}

.set-done {
  opacity: 0.65;
}

.set-device {
  font-size: 14px;
  color: var(--color-text-muted);
  background: var(--color-surface);
  border-left: 3px solid var(--color-primary);
  padding: 10px 12px;
  border-radius: 6px;
  margin: 0 0 16px;
}

/* One task per card */
.task-card {
  margin-bottom: 14px;
}

.task-heading {
  font-size: 16px;
  margin: 0 0 6px;
}

.task-instruction {
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-text-muted);
  margin: 0 0 18px;
}

.question {
  margin-bottom: 20px;
}

.question-text {
  font-size: 15px;
  font-weight: 600;
  margin: 0 0 10px;
  line-height: 1.4;
}

/* Whole row is tappable - these are mostly answered on a phone. */
.choice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 12px;
  margin-bottom: 6px;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-bg);
  font-size: 15px;
  line-height: 1.4;
  cursor: pointer;
  min-height: 44px;
}

.choice:has(input:checked) {
  border-color: var(--color-primary);
  background: var(--color-error-bg);
}

.choice input {
  margin-top: 2px;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: var(--color-primary);
}

.issue-block {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 12px;
}

.issue-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.remove-issue {
  background: none;
  border: none;
  color: var(--color-error);
  font-size: 13px;
  cursor: pointer;
  padding: 4px;
}

.secondary-button {
  width: 100%;
  padding: 12px;
  font-size: 15px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
  min-height: 44px;
}

.back-button {
  margin-top: 10px;
}

.done-card {
  text-align: center;
}

.done-card p {
  font-size: 15px;
  line-height: 1.5;
  color: var(--color-text-muted);
  margin-bottom: 20px;
}

/* --- Category-specific reminder (e.g. Misc Expenses) --- */

.category-notice {
  display: none;
  font-size: 13px;
  color: var(--color-error);
  background: var(--color-error-bg);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 16px;
}

.category-notice.visible {
  display: block;
}
