/*
 * freemcs.css — Tier-0 canonical design tokens · LOCKED 2026-05-22
 *
 * Single source of truth for :root tokens. Per Spruce 9-role review,
 * Tier-1 design work cannot land consistently across 9 personas until
 * these tokens are stable. DO NOT redefine these tokens in inline
 * <style> blocks — use page-local scopes (.scope-name {}) for variants.
 *
 * Per-skin variation: skin themes in web/skins/<slug>/ may override via
 * :root[data-skin="<slug>"] { --color-accent: ... } — that's the only
 * allowed :root override pattern.
 *
 * Token additions/changes require Tier-0 review.
 *
 * ----------------------------------------------------------------------------
 * Reconciliation history (2026-05-12 per audit-ui-polish.md §5; locked
 * 2026-05-22 per Spruce 9-role review): 3 conflicting CSS root systems
 * (freemcs.css / wizard.css / inline `<style>` blocks) collapsed onto the
 * picks below. wizard.css and polish.css mirror these values (and add motion
 * tokens). Per-skin variants in web/skins/_shared.css are intentionally
 * distinct (marketing pages, brand-prefixed namespaces).
 *
 *   --radius        : 12px      Spruce-tier per audit-spruce/scores.md
 *   --radius-sm     : 8px       sub-component radius
 *   --radius-lg     : 14px      modal / hero radius
 *   --bg            : #141413   most-used dark base
 *   --surface       : #1e1e1d   most-used surface
 *   --text          : #f5f0e8   warm off-white
 *   font-family     : 'Inter', system-ui, ...   (Inter for cross-platform
 *                                consistency; falls back to system-ui)
 * ========================================================================== */
:root{
  /* Surface + text — LIGHT. FreeMCS is a light product; these mirror the
     /home tokens so the whole app reads as one clean, trustworthy brand.
     (Dark mode was retired 2026-06 — it didn't suit FreeMCS.) */
  --bg:#f1f5f3;--bg-elevated:#f7faf9;--surface:#ffffff;--surface2:#eef4f1;
  /* dim text tokens darkened 2026-06-05 to meet WCAG 2.2 AA (>=4.5:1) on the
     lightest+darkest shared surfaces (#fff..#eef4f1). Same neutral green-grey
     hue family — no brand/skin change. Prior values (#8a988f / #a7b3ac) only
     reached ~2.0-3.0:1 and failed even large-text. */
  --text:#0f211b;--text2:#5d6f67;--text-muted:#62716a;--text-subtle:#647069;
  /* Accent (emerald) + variants */
  --accent:#10B981;--accent-hover:#047857;--accent-soft:rgba(16,185,129,0.12);--accent-strong:#047857;
  /* Status — darkened for legibility on light surfaces */
  --ok:#059669;--err:#dc2626;--success:#059669;--warn:#b9892b;--error:#dc2626;
  /* Border + radius */
  --border:#e3ebe7;--radius:12px;--radius-sm:8px;--radius-lg:14px;
  /* Motion (mirrored in polish.css) */
  --ease:cubic-bezier(0.2, 0.8, 0.2, 1);--ease-out:cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast:120ms;--dur-med:240ms;--dur-slow:420ms;
  /* Shadow — soft, tuned for light surfaces */
  --shadow-sm:0 1px 2px rgba(16,40,30,0.06);
  --shadow-md:0 8px 20px rgba(16,40,30,0.08);
  --shadow-lg:0 16px 40px rgba(16,40,30,0.12);
  /* Layout */
  --sidebar-w:200px;
}

/* Base */
body{font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased;min-height:100vh}

/* Layout */
.container{max-width:560px;margin:0 auto;padding:16px}

/* Header */
.header{background:var(--surface);padding:16px 20px;position:sticky;top:0;z-index:10;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--border)}
.header h1{font-size:18px;font-weight:700}
.header .sub{font-size:11px;color:var(--text2);margin-top:2px}
.header .tenant-badge{font-size:11px;background:var(--surface2);padding:4px 10px;border-radius:20px;color:var(--text2)}
.header .logout{background:none;border:1px solid var(--border);color:var(--text2);padding:6px 14px;border-radius:20px;cursor:pointer;font-size:11px}
.header .logout:hover{background:var(--surface2);color:var(--err);border-color:var(--err)}

/* Cards */
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:16px}
/* Heading text uses --accent-strong (darker emerald, 5.5:1 on white) instead of
   --accent (2.5:1, fails AA) — same brand hue, readable. --accent stays the
   button-background/skin-override token and is unchanged. */
.card h2{font-size:14px;font-weight:600;color:var(--accent-strong);margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.card h3{font-size:14px;font-weight:600;margin-bottom:12px;color:var(--accent-strong)}
.card:hover{border-color:var(--accent)}

/* Buttons */
.btn{display:block;width:100%;padding:16px;border:none;border-radius:var(--radius);font-size:16px;font-weight:600;cursor:pointer;transition:all .15s;text-align:center}
.btn-primary{background:var(--accent);color:#fff}
.btn-primary:hover{background:var(--accent-hover)}
.btn-primary:disabled{opacity:.4;cursor:not-allowed}
.btn-secondary{background:var(--surface2);color:var(--text);border:1px solid var(--border)}
.btn-secondary:hover{background:var(--border)}
.btn-success{background:var(--ok);color:#141413}
.btn-danger{background:rgba(248,113,113,.15);color:var(--err);border:1px solid var(--err)}
.btn-danger:hover{background:rgba(248,113,113,.25)}
.btn-sm{padding:6px 14px;font-size:12px}
.btn+.btn{margin-top:8px}

/* ============================================================================
 * Modal pattern — Tier-0 canonical (2026-05-22)
 *
 * Locked from wizard.css. `.modal-overlay` + `.modal` is THE pattern; the
 * legacy `.pl-modal-overlay` + `.pl-modal` pair (admin/job.html) is aliased
 * below for backwards-compat. New code must use `.modal-overlay` + `.modal`.
 * ========================================================================== */
.modal-overlay{position:fixed;inset:0;background:rgba(16,40,30,0.45);display:none;align-items:center;justify-content:center;z-index:100;padding:20px}
.modal-overlay.open{display:flex}
.modal{background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--radius-lg);padding:22px;width:100%;max-width:420px;display:flex;flex-direction:column;gap:14px;max-height:90vh;overflow-y:auto}
.modal h3{font-size:18px}

/* Legacy alias — admin/job.html quick-action modals. Do NOT use in new code. */
.pl-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.55);display:none;z-index:100}
.pl-modal-overlay.open{display:block;backdrop-filter:blur(2px)}


/* Forms */
.field-group,.field{margin-bottom:12px}
.field-group label,.field label{display:block;font-size:11px;font-weight:600;color:var(--text2);margin-bottom:4px;text-transform:uppercase;letter-spacing:.03em}
.field-group input,.field-group select,.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--border);border-radius:var(--radius-sm);background:var(--surface2);color:var(--text);font-size:16px;transition:border-color .15s;-webkit-appearance:none}
.field-group input:focus,.field-group select:focus,.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--accent)}
.field-group input::placeholder,.field input::placeholder{color:var(--text2);opacity:.5}

/* ============================================================================
 * Global keyboard focus ring — WCAG 2.2 AA (2.4.7 Focus Visible, 2.4.11/2.4.13
 * Focus Appearance). Added 2026-06-05.
 *
 * :focus-visible (not :focus) so pointer/touch users don't see a ring, but
 * every keyboard-tabbed control gets a clearly visible indicator. The ring is
 * --accent-strong (#047857, >=5:1 vs the light surfaces — clears the >=3:1
 * non-text-contrast bar) plus a soft white-then-accent halo so it stays
 * visible whether the element sits on a card, an accent button, or a coloured
 * status chip. We never remove outlines without supplying this replacement.
 * ========================================================================== */
:where(a,button,input,select,textarea,summary,[tabindex],[role="button"],[role="link"],[role="tab"],[role="menuitem"],[role="checkbox"],[role="radio"],[role="switch"],.btn,.tab,.header .logout,.room-card .remove,.detail-section .hdr):focus-visible{
  outline:2px solid var(--accent-strong);
  outline-offset:2px;
  border-radius:var(--radius-sm);
  box-shadow:0 0 0 2px var(--surface),0 0 0 4px var(--accent-soft);
}
/* Inputs already draw their own border; give keyboard focus a real ring back
   (the :focus rule above sets outline:none, which alone fails 2.4.7). */
.field-group input:focus-visible,.field-group select:focus-visible,.field input:focus-visible,.field select:focus-visible,.field textarea:focus-visible{
  outline:2px solid var(--accent-strong);
  outline-offset:0;
  border-color:var(--accent-strong);
  box-shadow:0 0 0 3px var(--accent-soft);
}
/* On filled accent/danger buttons the green ring can blend in — use a light
   halo + dark ring so the indicator keeps >=3:1 against the button fill. */
.btn-primary:focus-visible,.btn-success:focus-visible{
  outline-color:#0f211b;
  box-shadow:0 0 0 2px #ffffff,0 0 0 4px var(--accent-strong);
}
.field textarea{min-height:120px;font-family:monospace;font-size:12px;resize:vertical}
.field .hint{font-size:11px;color:var(--text2);margin-top:4px}

/* Grid layouts */
.dim-row{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px}
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.stat-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px}
.stat-row{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:8px;margin-bottom:16px}

/* Stats */
.stat-box{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:12px;text-align:center}
.stat-box .val{font-size:20px;font-weight:700;color:var(--accent-strong)}
.stat-box .lbl{font-size:11px;color:var(--text2);margin-top:2px}

/* Room cards */
.room-card{background:var(--surface2);border-radius:var(--radius-sm);padding:12px;margin-bottom:8px;border-left:3px solid var(--accent);position:relative}
.room-card .name{font-weight:600;font-size:13px}
.room-card .dims{font-size:11px;color:var(--text2);margin-top:4px}
.room-card .remove{position:absolute;top:8px;right:10px;background:none;border:none;color:var(--err);font-size:18px;cursor:pointer;padding:0;line-height:1}

/* Badges */
.badge{display:inline-block;padding:2px 8px;border-radius:20px;font-size:10px;font-weight:600}
.badge-green{background:rgba(52,211,153,.15);color:var(--ok)}
.badge-red{background:rgba(248,113,113,.15);color:var(--err)}
/* AA fix 2026-06-05: text was #fbbf24 (~1.5:1 on the pale-yellow chip — fails).
   #7a5f12 is the same amber family, darkened to ~5:1 on the chip background.
   The translucent chip background is unchanged (brand identity preserved). */
.badge-yellow{background:rgba(251,191,36,.15);color:#7a5f12}
.badge-gray{background:var(--surface2);color:var(--text2)}

/* Pills */
.pill{display:inline-block;padding:2px 8px;border-radius:20px;font-size:10px;font-weight:600}
.pill-green{background:rgba(52,211,153,.15);color:var(--ok)}
.pill-red{background:rgba(248,113,113,.15);color:var(--err)}
.pill-yellow{background:rgba(251,191,36,.15);color:#7a5f12}

/* Tables */
.u-table,table{width:100%;font-size:12px;border-collapse:collapse;margin-top:8px}
.u-table th,th{text-align:left;color:var(--text2);font-weight:600;padding:4px 8px;border-bottom:1px solid var(--border);font-size:10px;text-transform:uppercase}
.u-table td,td{padding:6px 8px;border-bottom:1px solid var(--border);color:var(--text)}
.u-table td:last-child,td:last-child{text-align:right}
tr.stale td{opacity:.6}

/* Utility */
.hidden{display:none!important}
.page{display:none}
.page.active{display:block}
.tab{display:none}
.tab.active{display:block}

/* Error/Success states */
.error-banner,.err-banner{background:rgba(248,113,113,.1);border:1px solid var(--err);color:var(--err);padding:12px;border-radius:var(--radius-sm);font-size:13px;margin-bottom:16px;display:none}
.error-banner.show,.err-banner.show{display:block}

/* Toast */
.toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--surface2);color:var(--text);padding:10px 20px;border-radius:24px;font-size:13px;border:1px solid var(--border);opacity:0;transition:opacity .3s;z-index:100;pointer-events:none}
.toast.show{opacity:1}

/* Spinner */
.spinner{display:inline-block;width:16px;height:16px;border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:spin .6s linear infinite;vertical-align:middle;margin-right:6px}
@keyframes spin{to{transform:rotate(360deg)}}

/* Animations */
@keyframes pulse{0%,100%{opacity:.4}50%{opacity:.8}}
.skeleton{background:var(--surface2);border-radius:var(--radius-sm);height:60px;margin-bottom:12px;animation:pulse 1.5s ease-in-out infinite}

/* Result specific */
.result-hero{background:linear-gradient(135deg,#1a3a2a,#0d2818);border-radius:var(--radius);padding:24px;text-align:center;margin-bottom:16px}
.result-hero .big{font-size:48px;font-weight:700;color:var(--ok)}
.result-hero .unit{font-size:16px;color:var(--ok);opacity:.8}
.result-hero .sub{font-size:12px;color:var(--text2);margin-top:4px}

/* HP recommendation */
.hp-card{border-left:3px solid var(--ok);background:var(--surface2)}
.hp-card h3{color:var(--ok);font-size:14px;font-weight:600;margin-bottom:8px}
.hp-card p{font-size:13px;color:var(--text);margin-bottom:4px}
.hp-card .small{font-size:11px;color:var(--text2)}

/* Detail sections */
.detail-section{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:16px;display:none}
.detail-section.open{display:block}
.detail-section .hdr{display:flex;justify-content:space-between;align-items:center;cursor:pointer;margin-bottom:8px}
.detail-section .hdr h3{font-size:13px;font-weight:600;color:var(--text)}
.detail-section .hdr .arrow{transition:transform .2s;color:var(--text2)}
.detail-section.open .hdr .arrow{transform:rotate(90deg)}

/* Scan prompt */
.scan-prompt{text-align:center;padding:16px;background:var(--surface2);border-radius:var(--radius-sm);margin-bottom:16px;border:1px dashed var(--border)}
.scan-prompt .icon{font-size:32px;margin-bottom:4px}
.scan-prompt h3{font-size:14px;color:var(--text);margin-bottom:2px}
.scan-prompt p{font-size:12px;color:var(--text2)}

/* Responsive */
@media(max-width:480px){
  .stat-grid{grid-template-columns:1fr 1fr}
  .stat-row{grid-template-columns:1fr 1fr}
  .dim-row{grid-template-columns:1fr}
  .grid-2{grid-template-columns:1fr}
  .container{padding:12px}
}
/* Narrowest phones (added 2026-06-05): collapse the dense 2-up grids to a
   single column so stat values/labels don't truncate, and shrink the result
   hero number so it can't overflow its card. Additive — no rule above changed. */
@media(max-width:360px){
  .stat-grid,.stat-row{grid-template-columns:1fr}
  .container{padding:10px}
  .result-hero{padding:18px}
  .result-hero .big{font-size:38px}
}

/* ============================================================================
 * Reduced motion — WCAG 2.2 (2.3.3 Animation from Interactions). Added
 * 2026-06-05. Honours the OS "reduce motion" setting: kill the looping spin /
 * pulse keyframes and collapse transitions to near-instant. The spinner stays
 * VISIBLE (it still conveys "loading"), it just stops rotating; the skeleton
 * shows at a fixed mid-opacity instead of pulsing. !important so it overrides
 * the page-local inline animations other pages may set.
 * ========================================================================== */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:0.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:0.001ms!important;
    scroll-behavior:auto!important;
  }
  .spinner{animation:none!important;border-top-color:var(--accent-strong)}
  .skeleton{animation:none!important;opacity:.6}
}

/* ============================================================================
 * W18.B — multi-role concurrent editing: presence avatars on the job page.
 * Wired by /js/job-presence.js. Each avatar is a 32px circle showing the
 * user's initials, role-coloured to make "who's editing what right now"
 * legible at a glance. -8px margin-left makes them stack/overlap like the
 * familiar Google-Docs viewer pattern.
 * ========================================================================== */
.presence-indicators{display:inline-flex;align-items:center;flex-wrap:wrap;gap:0;padding-left:8px}
.presence-avatar{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;background:var(--accent);color:#fff;font-size:12px;font-weight:600;margin-left:-8px;border:2px solid var(--surface);position:relative;cursor:default;line-height:1;flex:0 0 32px}
.presence-avatar:first-child{margin-left:0}
.presence-avatar[data-role="surveyor"]{background:#3b82f6}
.presence-avatar[data-role="engineer"]{background:#10b981}
.presence-avatar[data-role="technical-supervisor"]{background:#f59e0b}
.presence-avatar[data-role="inspector"]{background:#f59e0b}
.presence-avatar[data-role="operator"]{background:#ec4899}
.presence-avatar[data-role="admin"]{background:#a855f7}
/* Self avatar gets a faint ring so the user can spot themselves in the row. */
.presence-avatar[data-self="true"]{box-shadow:0 0 0 2px var(--accent-soft)}

/* ============================================================================
 * W18.C — field-level pessimistic locks. Wired by /js/field-locks.js.
 *
 *   * .is-self-locked    — the current user owns the lock; thin accent
 *                          border so they know they're now editing
 *                          exclusively.
 *   * .is-locked-by-other — another user is editing this field; we grey it
 *                          out + drop pointer-events so accidental typing
 *                          can't happen, and the role-coloured badge tells
 *                          them who.
 *   * .field-lock-badge  — 11px chip at the top-right of the locked field,
 *                          coloured by the locker's role (mirrors the
 *                          .presence-avatar palette above for visual
 *                          continuity).
 * ========================================================================== */
input.is-self-locked,select.is-self-locked,textarea.is-self-locked{border-color:var(--accent-strong);box-shadow:0 0 0 1px var(--accent-soft)}
input.is-locked-by-other,select.is-locked-by-other,textarea.is-locked-by-other{background:var(--bg-elevated);opacity:0.6;pointer-events:none;cursor:not-allowed;border-color:var(--border)}
.field-lock-badge{position:absolute;top:-8px;right:6px;display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:999px;background:var(--accent);color:#fff;font-size:11px;font-weight:600;line-height:1.4;letter-spacing:0.01em;pointer-events:auto;z-index:2;white-space:nowrap;max-width:160px;overflow:hidden;text-overflow:ellipsis;border:1px solid var(--surface)}
.field-lock-badge[data-role="surveyor"]{background:#3b82f6}
.field-lock-badge[data-role="engineer"]{background:#10b981}
.field-lock-badge[data-role="technical-supervisor"]{background:#f59e0b}
.field-lock-badge[data-role="inspector"]{background:#f59e0b}
.field-lock-badge[data-role="operator"]{background:#ec4899}
.field-lock-badge[data-role="admin"]{background:#a855f7}
