/* ============================================================
   Zubair Operations Hub — modern theme (PREVIEW, not live)
   Revision 2, after owner feedback:
     1. "I like the navy that used to show when opening tabs"
        → the navy header is back. Kept compact rather than the original
          tall block, so records still start near the top on a phone.
     2. "having a hard time reading the text"
        → measured, and it was failing: the label colour scored 3.47:1
          against white where 4.5:1 is the accessibility minimum, and the
          orange as text scored 3.05:1. The whole type scale was also too
          small. Both fixed — every colour below is measured, and body
          text is 16px, not 14px.
     3. Owner home redesigned around what an owner actually opens it for:
        what needs me today, then the money.

   This is a tool, not a page, so the craft is information design.
   Light ground on purpose: used outdoors in strong sun.
============================================================ */

:root{
  /* Ink — every value measured against white */
  --m-ink:        #0E1B2E;   /* 17.3:1  body                     */
  --m-ink-2:      #46566B;   /*  7.5:1  secondary                */
  --m-ink-3:      #566578;   /*  6.0:1  labels — was 3.47:1 FAIL */

  --m-ground:     #F4F6FA;
  --m-surface:    #FFFFFF;
  --m-surface-2:  #F9FAFC;
  --m-line:       #DFE5ED;
  --m-line-soft:  #EDF1F6;

  /* Navy — the header colour the owner asked to keep */
  --m-navy:       #0E1B2E;
  --m-navy-2:     #17293F;
  --m-on-navy:    #FFFFFF;   /* 17.3:1 on navy */
  --m-on-navy-2:  #B9C6D6;   /* 10.0:1 on navy */

  /* Accent. Two values on purpose: a fill that carries white text, and a
     darker one for orange AS TEXT, which needs more contrast. */
  --m-accent:      #B85400;  /* 4.9:1 with white on top */
  --m-accent-ink:  #A34A00;  /* 5.9:1 as text on white  */
  --m-accent-lift: #D46200;
  --m-accent-wash: #FDF1E6;

  /* Semantic — deliberately not the accent hue */
  --m-ok:   #0B6B43;  --m-ok-wash:   #E4F2EA;  --m-ok-line:   #A8D8BF;
  --m-warn: #8A5210;  --m-warn-wash: #FAEFDD;  --m-warn-line: #E4CB9C;
  --m-risk: #A01B14;  --m-risk-wash: #FBE9E7;  --m-risk-line: #EEBDB8;

  --m-r: 12px;  --m-r-sm: 9px;
  --m-shadow: 0 1px 2px rgba(14,27,46,.06), 0 1px 3px rgba(14,27,46,.05);
  --m-shadow-lift: 0 6px 18px rgba(14,27,46,.10);
}

/* Amounts align in columns and never break across lines. */
.kpi-value, .km-value, .cft strong, td.cell-num, .cell-num, .money,
table.data td, .ceo-chart-summary{ font-variant-numeric: tabular-nums; }

body, .admin-main{ background: var(--m-ground); color: var(--m-ink); }

/* ============================================================
   TYPE — the readability fix. Everything moved up a step.
============================================================ */
.admin-main{ font-size: 1rem; line-height: 1.55; }
table.data td{ font-size: .975rem; }
table.data th{ font-size: .78rem; letter-spacing: .06em; }
.sub-nav-tab{ font-size: .95rem; }
.filters label, .filters .form-row label{ font-size: .8rem; }
.filters input, .filters select{ font-size: 1rem; }
.badge{ font-size: .76rem; }

/* ---------- Sub navigation ---------- */
.sub-nav{
  display: flex; gap: 3px;
  padding: 6px; margin-bottom: 14px;
  background: var(--m-surface);
  border: 1px solid var(--m-line);
  border-radius: var(--m-r);
  box-shadow: var(--m-shadow);
  overflow-x: auto; scrollbar-width: none;
}
.sub-nav::-webkit-scrollbar{ display: none; }
.sub-nav-tab{
  padding: 10px 15px; border: none; border-radius: var(--m-r-sm);
  font-weight: 600; color: var(--m-ink-2); white-space: nowrap;
  transition: background .14s ease, color .14s ease;
}
.sub-nav-tab:hover{ background: var(--m-line-soft); color: var(--m-ink); }
.sub-nav-tab.active{ background: var(--m-navy); color: #fff; }

/* ============================================================
   NAVY PAGE HEADER — restored, but compact
============================================================ */
.page-hero{
  position: relative; overflow: hidden;
  padding: 18px 20px; margin-bottom: 14px;
  background: linear-gradient(135deg, var(--m-navy) 0%, var(--m-navy-2) 100%);
  border: none; border-radius: var(--m-r);
  box-shadow: var(--m-shadow);
  color: var(--m-on-navy);
  min-height: 0;
}
/* A single warm edge so the navy reads as branded, not just dark. */
.page-hero::after{
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--m-accent-lift), var(--m-accent));
}
.page-hero .page-head{
  /* flex-start, not center: centering the 42px buttons against the
     two-line title+subtitle block floated the title above the buttons —
     the header read as misaligned. Top-align and nudge the buttons to
     sit on the title's line. */
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px 18px; width: 100%;
}
.page-hero .page-actions{ margin-top: -3px; }
.page-hero .page-head > div:first-child{ flex: 1 1 240px; min-width: 0; }
.page-hero .page-head h1, .page-hero .page-head h2,
.page-hero h1, .page-hero h2{
  margin: 0;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 1.2rem; font-weight: 700; letter-spacing: -.01em;
  text-transform: none; color: var(--m-on-navy);
}
.page-hero p{
  margin: 5px 0 0; font-size: .9rem; line-height: 1.45; color: var(--m-on-navy-2);
}
.page-hero .page-actions{ display: flex; flex-wrap: wrap; gap: 8px; }
.page-hero .btn, .page-hero button{
  min-height: 42px; padding: 10px 16px;
  font-size: .92rem; font-weight: 600;
  border-radius: var(--m-r-sm); box-shadow: none;
  background: rgba(255,255,255,.10);
  border: 1px solid rgba(255,255,255,.20);
  color: #fff;
}
.page-hero .btn:hover{ background: rgba(255,255,255,.18); }
/* Exactly one coloured action per screen. */
.page-hero .btn-primary, .page-hero .btn-accent, .page-hero .btn:first-of-type{
  background: var(--m-accent); border-color: var(--m-accent); color: #fff;
}
.page-hero .btn-primary:hover, .page-hero .btn:first-of-type:hover{
  background: var(--m-accent-lift); border-color: var(--m-accent-lift);
}

/* ---------- Metric strip ----------
   Separate cards, not a joined slab. The old version drew hairlines by
   showing a grey GRID BACKGROUND through 1px gaps — which meant any row
   that wasn't full rendered its empty cells as one big grey box (visible
   on Expenses and Tenders, where 5 tiles sit in a 4-column grid). Cards
   with their own borders leave the page background in the gaps instead,
   and match the dashboard's kpi-mini tile language. */
.kpi-grid{
  display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: 10px; margin-bottom: 14px;
  background: transparent; border: none; border-radius: 0;
  overflow: visible; box-shadow: none;
}
.kpi-card{
  margin: 0; padding: 14px 16px; background: var(--m-surface);
  border: 1px solid var(--m-line); border-radius: var(--m-r);
  box-shadow: var(--m-shadow);
  display: flex; flex-direction: column; gap: 4px;
}
.kpi-card .kpi-label{
  font-size: .8rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--m-ink-3);
}
.kpi-card .kpi-value{
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 1.5rem; font-weight: 700; letter-spacing: -.02em;
  line-height: 1.15; color: var(--m-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kpi-card .kpi-foot{ font-size: .82rem; line-height: 1.4; color: var(--m-ink-3); }

/* ---------- Filters ---------- */
.filters{
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 14px;
  padding: 14px 16px; margin-bottom: 14px;
  background: var(--m-surface); border: 1px solid var(--m-line);
  border-radius: var(--m-r); box-shadow: var(--m-shadow);
}
.filters label, .filters .form-row label{
  font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--m-ink-3);
}
.filters input, .filters select{
  min-height: 44px; padding: 10px 12px; color: var(--m-ink);
  background: var(--m-surface-2); border: 1px solid var(--m-line);
  border-radius: var(--m-r-sm);
}
.filters input:focus, .filters select:focus{
  outline: none; border-color: var(--m-accent);
  background: var(--m-surface); box-shadow: 0 0 0 3px var(--m-accent-wash);
}

/* ---------- Records ---------- */
.table-wrap{
  background: var(--m-surface); border: 1px solid var(--m-line);
  border-radius: var(--m-r); box-shadow: var(--m-shadow);
}
table.data th{
  padding: 12px 15px; background: var(--m-surface-2);
  font-weight: 700; color: var(--m-ink-3);
  border-bottom: 1px solid var(--m-line);
}
table.data td{
  padding: 13px 15px; color: var(--m-ink);
  border-bottom: 1px solid var(--m-line-soft);
}
table.data tbody tr:hover{ background: var(--m-surface-2); }
table.data td.cell-num, table.data th.cell-num{ text-align: right; }

.badge{
  display: inline-flex; align-items: center; padding: 4px 10px;
  border-radius: 999px; font-weight: 700; border: 1px solid transparent;
}
.badge-success{ background: var(--m-ok-wash);   color: var(--m-ok);   border-color: var(--m-ok-line); }
.badge-warn, .badge-pending{ background: var(--m-warn-wash); color: var(--m-warn); border-color: var(--m-warn-line); }
.badge-danger{ background: var(--m-risk-wash); color: var(--m-risk); border-color: var(--m-risk-line); }
.badge-grey{ background: var(--m-line-soft); color: var(--m-ink-2); border-color: var(--m-line); }

/* ---------- Buttons ---------- */
.btn{ border-radius: var(--m-r-sm); font-weight: 600; font-size: .95rem; min-height: 44px; }
.btn:active{ transform: translateY(1px); }
.btn-primary, .btn-accent{ background: var(--m-accent); border-color: var(--m-accent); color: #fff; }
.btn-primary:hover, .btn-accent:hover{ background: var(--m-accent-lift); border-color: var(--m-accent-lift); }
.btn-ghost{ background: var(--m-surface); border: 1px solid var(--m-line); color: var(--m-ink); }
.btn-ghost:hover{ background: var(--m-line-soft); }

/* ---------- Top bar ---------- */
.admin-topbar{
  /* Solid white, same surface as the sidebar, so the header reads as one
     continuous band instead of two mismatched whites meeting at a seam. */
  background: var(--m-surface);
  border-bottom: 1px solid var(--m-line);
}
/* The old per-section pastel grounds (cream on the CEO section, lavender on
   Intelligence, …) and the faded 3px "section indicator strip" above the
   topbar predate this theme — together they produced the mismatched notch
   where sidebar, topbar and content meet. One ground everywhere. */
.admin-main::before{ display: none; }
body[class*="section-"] .admin-main,
body[class*="section-"] .module-container{ background: var(--m-ground); }
.topbar-search input{
  background: var(--m-surface-2); border: 1px solid var(--m-line);
  border-radius: 999px; min-height: 44px; font-size: 1rem;
}
.topbar-search input:focus{
  outline: none; border-color: var(--m-accent); box-shadow: 0 0 0 3px var(--m-accent-wash);
}

/* ============================================================
   OWNER HOME
   Ordered by what an owner opens it for: what needs me today,
   then the money. The action list is promoted above the charts.
============================================================ */
.dash-light-hero{
  position: relative; overflow: hidden;
  padding: 22px 22px 24px; margin-bottom: 18px;
  background: linear-gradient(135deg, var(--m-navy) 0%, var(--m-navy-2) 100%);
  border: none; border-radius: var(--m-r);
  box-shadow: var(--m-shadow-lift); color: var(--m-on-navy);
}
.dash-light-hero::after{
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--m-accent-lift), var(--m-accent));
}
.hero-pill{
  display: inline-block; margin-bottom: 12px; padding: 5px 12px;
  border-radius: 999px; font-size: .7rem; font-weight: 700;
  letter-spacing: .13em; text-transform: uppercase;
  color: #FFD5AC; background: rgba(212,98,0,.22);
  border: 1px solid rgba(212,98,0,.42);
}
.dash-light-hero .hero-text{ font-size: 1.42rem; font-weight: 700; line-height: 1.3; color: #fff; }
.dash-light-hero .hero-text .accent{ color: #FFB765; }
.dash-light-hero p, .dash-light-hero small{ color: var(--m-on-navy-2); font-size: .92rem; }

.dash-section-title{
  margin: 22px 0 10px;
  font-size: .84rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--m-ink-3);
}

/* Metric tiles with sparklines */
.kpi-strip{
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; margin-bottom: 4px;
}
.kpi-mini .km-foot{ font-variant-numeric: tabular-nums; }
/* When a tile's tint is semantic (negative net, money owed), the number
   carries the state too — with the label text, never colour alone. */
.kpi-mini.tint-red .km-value{ color: #b91c1c; }
.kpi-mini.tint-green .km-value{ color: #15803d; }

/* Fingers, not cursors: 30px row buttons are below the 44px minimum touch
   target. Bigger only on coarse pointers so dense desktop tables stay dense. */
@media (pointer: coarse){
  .row-actions .icon-btn{ width: 40px; height: 40px; font-size: 1.05rem; }
}
.kpi-mini{
  display: flex; flex-direction: column; gap: 5px;
  padding: 15px 16px; background: var(--m-surface);
  border: 1px solid var(--m-line); border-radius: var(--m-r);
  box-shadow: var(--m-shadow);
  transition: box-shadow .16s ease, transform .16s ease;
}
.kpi-mini:hover{ box-shadow: var(--m-shadow-lift); transform: translateY(-1px); }
.km-label{
  font-size: .8rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--m-ink-3);
}
.km-value{
  font-size: 1.48rem; font-weight: 700; letter-spacing: -.02em;
  color: var(--m-ink); white-space: nowrap;
}
.km-foot{ font-size: .82rem; color: var(--m-ink-3); }
.sparkline{ margin: 2px 0; opacity: .9; }

/* The action list — the reason an owner opens this screen */
.todays-action{
  margin: 18px 0; background: var(--m-surface);
  border: 1px solid var(--m-line); border-left: 3px solid var(--m-accent);
  border-radius: var(--m-r); box-shadow: var(--m-shadow); overflow: hidden;
}
.ta-head{
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 15px 18px; background: var(--m-surface-2);
  border-bottom: 1px solid var(--m-line);
  font-size: 1.02rem; font-weight: 700; color: var(--m-ink);
}
.ta-count{
  padding: 4px 11px; border-radius: 999px;
  font-size: .76rem; font-weight: 700;
  background: var(--m-accent-wash); color: var(--m-accent-ink);
  border: 1px solid #F0CBA5;
}
.ta-list{ display: flex; flex-direction: column; }
.ta-item{
  display: flex; align-items: center; gap: 13px;
  padding: 14px 18px; min-height: 56px;
  border-bottom: 1px solid var(--m-line-soft);
  font-size: .975rem; color: var(--m-ink); cursor: pointer;
  transition: background .14s ease;
}
.ta-item:last-child{ border-bottom: none; }
.ta-item:hover{ background: var(--m-accent-wash); }
.ta-icon{ flex: 0 0 auto; font-size: 1.1rem; }
.ta-text{ flex: 1; line-height: 1.45; }
.ta-arrow{ flex: 0 0 auto; color: var(--m-ink-3); font-size: 1.15rem; }
.ta-item:hover .ta-arrow{ color: var(--m-accent-ink); }

/* Charts and data cards */
.data-card{
  background: var(--m-surface); border: 1px solid var(--m-line);
  border-radius: var(--m-r); box-shadow: var(--m-shadow);
  overflow: hidden; margin-bottom: 14px;
}
.data-card-head{
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 10px 16px; padding: 15px 18px;
  background: var(--m-surface-2); border-bottom: 1px solid var(--m-line);
  font-size: 1rem; font-weight: 700; color: var(--m-ink);
}
.ceo-cashflow-totals{ display: flex; flex-wrap: wrap; gap: 10px 22px; }
.cft{ display: flex; flex-direction: column; gap: 2px; font-size: .8rem; color: var(--m-ink-3); }
.cft strong{ font-size: 1.06rem; font-weight: 700; color: var(--m-ink); white-space: nowrap; }
.ceo-chart-wrap{ padding: 16px 18px; }
.ceo-chart-summary{ font-size: 1.2rem; font-weight: 700; color: var(--m-ink); }
.dash-grid{ display: grid; gap: 14px; }

/* ---------- Sidebar ----------
   The sidebar ships WHITE: a `background:#fff !important` from the older
   light-sidebar era in style.css beats the navy that used to be set here,
   so the navy never rendered — but its on-navy item colour (#B6C4D6) did,
   leaving pale-blue text on white at 1.9:1. Style the sidebar for what it
   actually is: light surface, measured ink tokens. */
.sidebar{ background: var(--m-surface); border-right: 1px solid var(--m-line); }
.sidebar .sidebar-brand strong{ color: var(--m-ink); }
.sidebar .sidebar-brand small{ color: var(--m-ink-3); }
.nav-section-btn{
  margin: 2px 8px; padding: 11px 13px; border-radius: var(--m-r-sm);
  font-size: .95rem; font-weight: 600; color: var(--m-ink-2);   /* 7.5:1 */
  transition: background .14s ease, color .14s ease;
}
.nav-section-btn .nav-icon{ background: var(--m-line-soft); color: var(--m-ink-2); }
.nav-section-btn:hover{ background: var(--m-line-soft); color: var(--m-ink); }
.nav-section-btn:hover .nav-icon{ background: var(--m-line); color: var(--m-ink); }
.nav-section-btn.active{ background: var(--m-accent-wash); color: var(--m-accent-ink); }   /* 5.9:1 */
.nav-section-btn.active .nav-icon{ background: var(--m-accent); color: #fff; }

/* ============================================================
   PHONE LAYERS — width only, deliberately NOT "(pointer: coarse)"
   Every block below used to read
       @media (max-width: 760px), (hover: none) and (pointer: coarse)
   and an iPad answers yes to the second half at ANY width. So a 1024px
   iPad picked up the phone treatment: four of the five header buttons
   were hidden (CSV export among them), the filter bar collapsed, and
   `.table-wrap{overflow-x:visible}` was applied WITHOUT the card layout
   that justifies it — style.css turns rows into cards at 760px only,
   so tables simply spilled off the side of the screen.

   The phone layers are now bounded at 760px, the same breakpoint
   style.css already uses for the card layout, so the two agree.
   A 768–1024px iPad gets the full desktop-style layout, which is what
   an office admin needs. Tap-target and font-size rules stay keyed to
   (pointer: coarse) — those SHOULD apply on an iPad.
============================================================ */

/* ---------- Phones ---------- */
@media (max-width: 760px){
  .page-hero{ padding: 15px 16px; }
  .page-hero .page-head h1, .page-hero .page-head h2{ font-size: 1.1rem; }
  .page-hero p{ display: none; }   /* repeats on every visit; space is scarce */
  .kpi-grid{ grid-template-columns: repeat(2, 1fr); }
  .kpi-card .kpi-value{ font-size: 1.3rem; }
  .dash-light-hero{ padding: 18px 17px 20px; }
  .dash-light-hero .hero-text{ font-size: 1.2rem; }
  .km-value{ font-size: 1.32rem; }
  .kpi-strip{ grid-template-columns: repeat(2, 1fr); }
  .ta-item{ padding: 14px 15px; }

  table.data tr{
    border: 1px solid var(--m-line); border-radius: var(--m-r);
    box-shadow: var(--m-shadow); margin-bottom: 10px; overflow: hidden;
  }
  table.data td{ padding: 12px 14px; }
  table.data td[data-label]::before{
    font-size: .78rem; letter-spacing: .06em; color: var(--m-ink-3);
  }
}

/* Matches the breakpoint that actually shows the bar (style.css). */
@media (max-width: 760px){
  .tabbar{ background: rgba(255,255,255,.97); border-top: 1px solid var(--m-line); }
  .tab{ color: var(--m-ink-3); }
  .tab-tx{ font-size: .72rem; }
  .tab.active{ color: var(--m-accent-ink); }
}

@media (prefers-reduced-motion: reduce){
  *{ animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ============================================================
   DECLUTTER — phone only (paired with preview/declutter.js)
   Owner: "still feels very cluttered" / "improve the mobile version".
   On Projects, five blocks sat above the first record and six of the
   seven status chips read "0". Nothing is removed — everything below is
   one tap away. This only stops empty and rarely-touched controls from
   taking the first screenful.
============================================================ */
@media (max-width: 760px){

  /* Zero-count status chips fold away behind "+N more". */
  [data-zc-empty]{ display: none; }
  .zc-show-empty [data-zc-empty]{ display: inline-flex; }

  .zc-showall{
    display: inline-flex; align-items: center;
    min-height: 38px; padding: 7px 13px; margin-left: 4px;
    font: inherit; font-size: .84rem; font-weight: 600;
    color: var(--m-ink-2); background: var(--m-surface);
    border: 1px dashed var(--m-line); border-radius: 999px; cursor: pointer;
  }
  .zc-showall:hover{ background: var(--m-line-soft); color: var(--m-ink); }

  /* Filters collapse behind a button that reports how many are active. */
  .filters, .proj-toolbar{ display: none; }
  .filters.zc-open, .proj-toolbar.zc-open{ display: flex; }

  .zc-filter-toggle{
    display: inline-flex; align-items: center; gap: 8px;
    min-height: 44px; padding: 10px 16px; margin-bottom: 12px;
    font: inherit; font-size: .92rem; font-weight: 600;
    color: var(--m-ink); background: var(--m-surface);
    border: 1px solid var(--m-line); border-radius: var(--m-r-sm);
    box-shadow: var(--m-shadow); cursor: pointer;
  }
  .zc-filter-toggle::before{ content: '⚲'; font-size: 1rem; color: var(--m-ink-3); }
  .zc-filter-toggle.zc-has-filters{
    color: var(--m-accent-ink);
    border-color: #E9C39C;
    background: var(--m-accent-wash);
  }
  .zc-filter-toggle.zc-has-filters::before{ color: var(--m-accent-ink); }

  /* Metrics: two on screen, the rest on request. */
  [data-zc-extra]{ display: none !important; }
  .zc-show-extra [data-zc-extra]{ display: flex !important; }
  .zc-metrics-toggle{
    display: block; width: 100%;
    min-height: 42px; padding: 10px; margin: -6px 0 14px;
    font: inherit; font-size: .88rem; font-weight: 600;
    color: var(--m-ink-2); background: var(--m-surface);
    border: 1px solid var(--m-line); border-top: none;
    border-radius: 0 0 var(--m-r) var(--m-r);
    cursor: pointer;
  }
  .zc-metrics-toggle:hover{ background: var(--m-line-soft); color: var(--m-ink); }

  /* Tighten the remaining rhythm so less scrolling is needed overall. */
  .sub-nav{ margin-bottom: 10px; padding: 5px; }
  .page-hero{ margin-bottom: 10px; }
  .kpi-grid{ margin-bottom: 0; }
  .proj-tabs-row{ display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
}

/* ============================================================
   THE MOBILE BUG
   Measured on a real 375px screen: the app laid out 590px wide, i.e.
   215px of horizontal overflow, with 54 elements wider than the phone.
   That is why it "doesn't work good on mobile" — content was pushed
   off-screen and every screen needed sideways scrolling.

   Cause: #adminApp is a CSS grid whose single column sized itself to its
   CONTENT (590px) rather than to the screen. A grid or flex item refuses
   to shrink below its max-content width unless told to, so the whole app
   inherited the width of its widest row — the top bar.

   Fix: minmax(0, 1fr) on the track plus min-width:0 on the item, which is
   the specific pair that allows shrinking. Everything else here stops
   individual rows re-inflating it.

   This one KEEPS (pointer: coarse) on purpose, unlike the phone layers
   above: it hides nothing and removes nothing, it only stops the page
   itself scrolling sideways. An iPad still wants that.
============================================================ */
@media (max-width: 900px), (hover: none) and (pointer: coarse){
  #adminApp{
    grid-template-columns: minmax(0, 1fr) !important;
    width: 100%;
    max-width: 100vw;
    overflow-x: hidden;
  }
  .admin-main{
    min-width: 0 !important;
    max-width: 100vw;
    width: 100%;
    overflow-x: hidden;
  }
  .module-container{ min-width: 0; max-width: 100%; overflow-x: hidden; }

  /* The top bar was the widest row and set the floor for everything else. */
  .admin-topbar{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 10px;
    min-width: 0;
    padding: 10px 12px;
  }
  .topbar-search{ flex: 1 1 100%; min-width: 0; order: 2; }
  .topbar-search input{ width: 100%; min-width: 0; }
  .topbar-actions{
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
    order: 1;
  }
  .user-pill{ max-width: 46vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Rows that legitimately exceed the screen scroll inside themselves
     rather than widening the page. */
  .sub-nav, .proj-tabs-row, .kpi-strip{ max-width: 100%; }
  .page-hero, .page-hero .page-head, .kpi-grid,
  .filters, .proj-toolbar, .table-wrap, .data-card, .todays-action{
    max-width: 100%;
    min-width: 0;
  }
  .page-hero .page-head > div:first-child{ flex: 1 1 100%; }
  .page-hero .page-actions{ width: 100%; }
  .page-hero .btn{ flex: 1 1 auto; justify-content: center; }

  /* Long words and unbroken IDs must not push the layout wide. */
  .module-container, .page-hero, table.data td{ overflow-wrap: anywhere; }
}

/* ============================================================
   OWNER HOME — photograph behind the greeting
   A real site photo rather than a flat gradient, with a navy scrim heavy
   enough to keep the white text at an accessible contrast (verified in
   the browser, not assumed).
============================================================ */
.dash-light-hero{
  background-image:
    linear-gradient(115deg, rgba(9,18,32,.94) 0%, rgba(11,22,38,.86) 42%, rgba(14,27,46,.66) 100%),
    url('/assets/guyana-1.jpg');
  background-size: cover;
  background-position: center 38%;
  background-repeat: no-repeat;
}

/* style.css still paints the hero heading #0a1628 — correct for the old cream
   banner, invisible on a dark photograph. Only the orange .accent word was
   legible, so "Building One Guyana." read as just "Guyana". */
.dash-light-hero h2{ color:#fff; }
.dash-light-hero h2 .accent{ color:#FFB765; }
.dash-light-hero .hero-pill{
  background:rgba(255,255,255,.14);
  border:1px solid rgba(255,255,255,.28);
  color:#FFD9AE;
  backdrop-filter:blur(6px);
}
@media (max-width: 760px){
  /* Portrait crop keeps the machinery visible instead of a patch of sky. */
  .dash-light-hero{
    background-position: center 45%;
    background-image:
      linear-gradient(160deg, rgba(9,18,32,.95) 0%, rgba(11,22,38,.88) 55%, rgba(14,27,46,.74) 100%),
      url('/assets/guyana-1.jpg');
  }
}

/* ------------------------------------------------------------
   The owner's own home (CEO dashboard) gets its own photograph so
   the two landing screens are not identical: the bridge build at
   golden hour, whose warm tone carries the brand orange.

   It is a much brighter frame than guyana-1, so the scrim is
   heavier on the left where the greeting sits and clears to the
   right, letting the cranes read. Verified in-browser for contrast
   rather than assumed.
------------------------------------------------------------ */
.dash-light-hero.hero-owner{
  background-image:
    linear-gradient(100deg, rgba(9,18,32,.95) 0%, rgba(10,20,35,.88) 38%, rgba(12,24,42,.55) 72%, rgba(14,27,46,.34) 100%),
    url('/assets/guyana-4.jpg');
  background-size: cover;
  background-position: center 52%;
  background-repeat: no-repeat;
}
@media (max-width: 760px){
  .dash-light-hero.hero-owner{
    background-position: 62% 50%;
    background-image:
      linear-gradient(160deg, rgba(9,18,32,.95) 0%, rgba(11,22,38,.9) 55%, rgba(14,27,46,.72) 100%),
      url('/assets/guyana-4.jpg');
  }
}

/* An old rule, `.view-admin table.data{ min-width:560px }`, forced every
   table 560px wide to guarantee sideways scrolling. That predates the card
   layout and defeats it: rows became cards but the table still could not
   shrink below 560px inside a 347px wrapper, so records still scrolled
   sideways on a phone. Specificity (0,2,1) needs matching to undo. */
@media (max-width: 760px){
  .view-admin table.data,
  table.data{
    min-width: 0 !important;
    width: 100% !important;
  }
  .table-wrap{
    overflow-x: visible;   /* cards reflow; there is nothing to scroll to */
    background: transparent;
    border: none;
    box-shadow: none;
  }
}

/* ============================================================
   VERTICAL SPACE — measured: 957px of chrome before the first record
   on an 812px screen, i.e. more than a full screen of scrolling before
   any data. Biggest culprits: the section tabs wrapped onto three rows,
   the top bar onto two, and the header buttons stacked.
============================================================ */
@media (max-width: 760px){
  /* Tabs scroll sideways in ONE row instead of wrapping to three. */
  .sub-nav{
    flex-wrap: nowrap !important;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding: 4px;
    margin-bottom: 8px;
  }
  .sub-nav-tab{ flex: 0 0 auto; padding: 9px 13px; }

  /* Top bar on one line: search takes the room, the rest stays compact. */
  .admin-topbar{
    flex-wrap: nowrap;
    padding: 8px 10px;
    gap: 8px;
    min-height: 0;
  }
  .topbar-search{ flex: 1 1 auto; order: 0; min-width: 0; }
  .topbar-search input{ min-height: 40px; font-size: 1rem; }
  .topbar-actions{ flex: 0 0 auto; order: 1; flex-wrap: nowrap; }
  /* The sync state is the important pill; the role label is not worth a row. */
  .topbar-actions .user-pill{ display: none; }
  #syncStatus{ font-size: .74rem; padding: 6px 10px; }

  /* Header: title and actions share the space instead of stacking. */
  .page-hero{ padding: 12px 14px; margin-bottom: 8px; }
  .page-hero .page-head{ gap: 8px 10px; }
  .page-hero .page-head > div:first-child{ flex: 1 1 100%; }
  .page-hero .page-actions{ width: 100%; flex-wrap: nowrap; gap: 6px; }
  .page-hero .btn{
    flex: 1 1 0; min-width: 0; min-height: 40px;
    padding: 9px 8px; font-size: .86rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }

  .kpi-grid{ margin-bottom: 0; }
  .kpi-card{ padding: 11px 13px; }
  .kpi-card .kpi-foot{ display: none; }   /* the caption repeats the label */
}

/* ============================================================
   MOBILE REVIEW MODE
   Phone and iPad mini are for the owner CHECKING, not entering.
   A record reads as a summary — what it is, what it cost, its state —
   and expands only if he wants the detail.

   Roughly 90px per record instead of ~600px: eight records on screen
   instead of one.
============================================================ */
@media (max-width: 760px){

  /* The labelled field list collapses; the summary stands in for it. */
  .zc-summarised > td{ display: none !important; }
  .zc-summarised.zc-expanded > td{ display: flex !important; }
  .zc-summarised.zc-expanded > td.row-actions{ display: flex !important; }

  .zc-sum{
    display: flex !important;
    align-items: flex-start;
    gap: 12px;
    padding: 13px 15px;
    min-height: 62px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .zc-sum-main{ flex: 1 1 auto; min-width: 0; }
  .zc-sum-title{
    font-size: 1rem; font-weight: 600; line-height: 1.35; color: var(--m-ink);
    overflow: hidden; text-overflow: ellipsis;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  }
  .zc-sum-meta{
    margin-top: 3px;
    font-size: .84rem; line-height: 1.35; color: var(--m-ink-3);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .zc-sum-side{
    flex: 0 0 auto; display: flex; flex-direction: column;
    align-items: flex-end; gap: 5px; text-align: right;
  }
  .zc-sum-amount{
    font-size: 1rem; font-weight: 700; color: var(--m-ink);
    white-space: nowrap; font-variant-numeric: tabular-nums;
  }
  .zc-sum-status .badge{ font-size: .7rem; padding: 3px 8px; }

  /* A hairline chevron hints the row opens, without shouting. */
  .zc-summarised{ position: relative; }
  .zc-summarised .zc-sum::after{
    content: '›';
    align-self: center;
    font-size: 1.2rem;
    color: var(--m-line);
    transition: transform .18s ease, color .18s ease;
  }
  .zc-summarised.zc-expanded .zc-sum::after{
    transform: rotate(90deg);
    color: var(--m-accent-ink);
  }
  .zc-summarised.zc-expanded{ box-shadow: var(--m-shadow-lift); }
  .zc-summarised.zc-expanded .zc-sum{
    border-bottom: 1px solid var(--m-line-soft);
    background: var(--m-surface-2);
  }

  /* Tighter cards so more records fit the screen. */
  table.data tr{ margin-bottom: 8px; }
  table.data tr.zc-summarised > td{ padding: 10px 15px; }
  table.data tr.zc-summarised > td[data-label]::before{ flex: 0 0 38%; }

  /* Totals row keeps its own shape. */
  table.data tr[style*="background"]{ background: var(--m-surface-2) !important; }
}

/* ============================================================
   Data entry belongs on the desktop; the phone is for checking.
   CSV, Print and other desk tasks are hidden on a phone, and the header
   collapses to a single line, so the screen is spent on records.
   The primary action stays — occasionally something is added on site.
============================================================ */
@media (max-width: 760px){
  .page-hero .page-actions .btn:not(:first-of-type){ display: none; }

  /* COLUMN, not row.
     This was `display:flex; align-items:center`, which made the HERO itself a
     single non-wrapping row. The intent was only to put the title beside its
     action — that is the .page-head rule below — but the hero also holds the
     KPI strip and the "Show n more" toggle as siblings, so all three were
     crammed into 347px. The strip was squeezed to 81px, its two tiles to 35px
     each, and the labels wrapped one letter per line: "Q U E U E D" stacked
     vertically down a 352px-tall sliver, with the action button overlapping
     the number. Stacking gives the strip the full width it needs. */
  .page-hero{
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    padding: 11px 14px; margin-bottom: 8px;
  }
  /* Full width once stacked, and never narrower than two readable tiles. */
  .page-hero .kpi-strip{
    width: 100%;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  }
  .page-hero .zc-metrics-toggle{ width: 100%; }
  /* The base stylesheet stacks these in a column; on a phone the title and
     its one action belong on the same line. */
  .page-hero .page-head{
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: center;
    gap: 10px;
  }
  /* The title owns at least a third of the row — without a floor, wide action
     buttons squeeze it to an unreadable "Aut…" (or, at its worst, 0px). */
  .page-hero .page-head > div:first-child{ flex: 1 1 auto; min-width: 34%; text-align: left; }
  .page-hero .page-head h1, .page-hero .page-head h2{
    font-size: 1.02rem; text-align: left;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* The head above is nowrap, so the actions must NOT take width:100% here —
     but the ".page-hero .page-actions{ width:100% }" rule in the later 900px
     block outranks a same-specificity rule by source order and was collapsing
     the title to 0px. The extra .page-head level wins on specificity instead. */
  .page-hero .page-head > .page-actions{ width: auto; flex: 0 1 auto; min-width: 0; }
  .page-hero .page-actions .btn{
    /* 0 1, not 0 0: buttons give way (ellipsising their label) rather than
       push the title out of its 34% floor above. */
    flex: 0 1 auto; min-width: 0; min-height: 38px; padding: 8px 14px; font-size: .86rem;
  }
}

/* ============================================================
   PRINT — reports must survive the printer
   theme-modern.css had no print rules at all, so the Reports page
   printed its title white-on-white: applyPageHero() wraps the
   report heading in .page-hero, which is painted with a dark navy
   gradient and given white text — and browsers drop background
   images and gradients when printing. The heading stayed white,
   the navy behind it did not.

   style.css:1275 already neutralises .dash-hero-banner and
   .section-hero this way; .page-hero and .dash-light-hero were
   simply never added to that list.
============================================================ */
@media print{
  .page-hero,
  .dash-light-hero,
  .dash-light-hero.hero-owner{
    background: #fff !important;
    background-image: none !important;
    color: #000 !important;
    border: 0 !important;
    box-shadow: none !important;
    height: auto !important;
    padding: 0 0 8px !important;
  }
  .page-hero *,
  .dash-light-hero *{ color: #000 !important; }
  .dash-light-hero .accent{ color: #000 !important; }
  .dash-light-hero::before,
  .dash-light-hero::after{ display: none !important; }

  /* Screen furniture that must not appear on paper. .tabbar in
     particular becomes position:fixed under 760px, and a print
     viewport is narrow enough to match — it would otherwise stamp
     itself across the page. */
  .sub-nav,
  .tabbar,
  .fab,
  .sidebar,
  .sidebar-backdrop,
  .scrim,
  .filters .btn,
  .hero-actions,
  .page-actions{ display: none !important; }

  /* Let long reports break sensibly rather than clipping. */
  .table-wrap{ overflow: visible !important; }
  table.data{ width: 100% !important; }
  table.data tr{ break-inside: avoid; page-break-inside: avoid; }
  thead{ display: table-header-group; }
  .report-total-row{ break-inside: avoid; }
}

/* ============================================================
   iOS SAFARI ZOOM — the one that made forms unusable
   Mobile Safari zooms the whole page in when a focused text field
   computes below 16px, and it does NOT zoom back out afterwards. A
   supervisor who taps into an expense form is left on a magnified,
   sideways-scrolling page for the rest of the session, and nothing on
   screen tells him how to get out of it.

   Fourteen rules across style.css set field text between .84rem and
   .95rem (13.4px–15.2px) — .form-row, .filters .form-row,
   .topbar-search, .proj-filter-row, .cf-search, .career-filters,
   .src-main/.src-meta and the payroll .c-rate box — plus one inline
   style on the WhatsApp bridge URL field. style.css already had
   `input, select, textarea{font-size:16px}` for coarse pointers, but at
   specificity (0,0,1) every one of those class-based rules beat it, so
   it never actually applied to a single real field.

   Hence !important: this must outrank ~14 more specific selectors in
   another file plus an inline style, and an arms race of longer
   selectors would be worse to maintain. Scoped to narrow viewports and
   touch devices so desktop typography is untouched. Controls that never
   trigger the zoom (checkbox, radio, range, colour, button-like inputs)
   are left alone so nothing shifts in layout.
============================================================ */
@media (max-width: 820px), (hover: none) and (pointer: coarse){
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="button"]):not([type="submit"]):not([type="reset"]),
  select,
  textarea{
    font-size: 16px !important;
  }
}

/* ============================================================
   DECLUTTER SCRIPT — keep it off the iPad too
   mobile-review.js decides what to fold away with the same media query
   the CSS above used to use, so it still runs on an iPad and injects
   its controls there: a summary line inside every table row, a
   "Filters" toggle, "+N more" chips, "Show N more" under the metrics.
   Those elements are only styled inside the phone layer, so above 760px
   they would render as stray, dead buttons and a duplicated row.

   mobile-review.js is not ours to edit in this pass, so the injected
   markup is neutralised here. Nothing is lost: above 760px the real
   filter bar, the full chip row and every metric tile are all visible,
   which is exactly what those controls existed to reveal.
   Handoff: the two matchMedia() strings in mobile-review.js should be
   narrowed to '(max-width: 760px)' so the work is not done at all.
============================================================ */
@media (min-width: 761px){
  .zc-sum,
  .zc-showall,
  .zc-filter-toggle,
  .zc-metrics-toggle{ display: none !important; }
}

/* ============================================================
   View toggles — a segmented control, not two buttons

   These read "Cards / Table" and "List / Board". They used emoji as
   icons (🃏 📋 🪜 ☰ ▦), which sit on a different baseline to the text
   beside them and render as a different picture on every platform —
   a playing card on one phone, a blank box on another. The words
   already say what the control does, so the icons were carrying no
   meaning and costing consistency. Removed.

   What communicates state is the filled pill on the selected option,
   which is what a segmented control is for. Inside the navy hero the
   same control has to work on a dark ground, hence the second block.
============================================================ */
.view-toggle{
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: var(--m-surface-2);
  border: 1px solid var(--m-line);
  border-radius: 99px;
  margin-right: 8px;
}
.view-toggle button{
  appearance: none;
  border: none;
  background: transparent;
  border-radius: 99px;
  padding: 7px 16px;
  min-height: 38px;
  font: inherit;
  font-size: .86rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--m-ink-3);
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s ease, color .15s ease;
}
.view-toggle button:hover{ background: var(--m-line-soft); color: var(--m-ink); }
.view-toggle button.active{
  background: var(--m-navy);
  color: #fff;
  box-shadow: 0 1px 2px rgba(14,27,46,.18);
}
.view-toggle button:focus-visible{
  outline: 2px solid var(--m-accent);
  outline-offset: 1px;
}

/* On the navy hero the light chrome would disappear, so invert it. */
.page-hero .view-toggle,
.dash-light-hero .view-toggle{
  background: rgba(255,255,255,.10);
  border-color: rgba(255,255,255,.20);
}
.page-hero .view-toggle button,
.dash-light-hero .view-toggle button{ color: rgba(255,255,255,.72); }
.page-hero .view-toggle button:hover,
.dash-light-hero .view-toggle button:hover{
  background: rgba(255,255,255,.12); color: #fff;
}
.page-hero .view-toggle button.active,
.dash-light-hero .view-toggle button.active{
  background: #fff; color: var(--m-navy); box-shadow: none;
}

/* On a phone the pair should fill the width rather than huddle in a corner. */
@media (max-width: 760px){
  .view-toggle{ display: flex; width: 100%; margin-right: 0; }
  .view-toggle button{ flex: 1 1 0; padding: 8px 10px; }
}

/* ============================================================
   Phone: a view toggle gets its own line

   The phone rule keeps the title and its one action on a single
   row to save vertical space, which is right — until the screen
   also has a List/Board or Cards/Table toggle. Three things then
   compete for 375px and the title loses, collapsing to "Ten…".

   Where a toggle is present, the title takes the full first line
   and the controls sit beneath it. :has() is the whole condition,
   so a browser without it simply keeps the old single-row
   behaviour rather than getting a broken variant.
============================================================ */
@media (max-width: 760px){
  .page-hero .page-head:has(.view-toggle){
    flex-wrap: wrap !important;
    row-gap: 10px;
  }
  .page-hero .page-head:has(.view-toggle) > div:first-child{
    flex: 1 1 100%;
    min-width: 0;
  }
  .page-hero .page-head:has(.view-toggle) h1,
  .page-hero .page-head:has(.view-toggle) h2{
    white-space: normal;        /* it has the room now; stop truncating */
  }
  .page-hero .page-actions:has(.view-toggle){
    width: 100%;
    align-items: center;
    gap: 8px;
  }
  /* Toggle takes the space it needs; the action keeps its own size. */
  .page-hero .page-actions:has(.view-toggle) .view-toggle{ flex: 1 1 auto; width: auto; }
  .page-hero .page-actions:has(.view-toggle) .btn{ flex: 0 0 auto; }
}

/* ============================================================
   UI SWEEP FIXES — measured at 375 / 700 / 900 / 1280
   Loaded last on purpose: these correct earlier layers rather
   than replacing them, so the reasoning stays next to the fix.
============================================================ */

/* ---- 1. Tables were being shredded into one letter per line ----
   `overflow-wrap: anywhere` was applied to table cells for every viewport
   under 900px AND every touch device of any size. `anywhere` participates in
   min-content sizing, so an auto-layout table collapses each column to its
   narrowest possible box and then breaks the words to fit: "GY / D / 2,4 /
   50, / 00 / 0", headers reading "S / U / P / PLI / ER". It hit the 761-900px
   band and — because of the pointer rule — iPad landscape at 1024px too, so
   the office admin's tablet showed unreadable money.

   `break-word` does the job it was added for (a long unbroken ID cannot widen
   the page) without collapsing the columns. Above phone width the table keeps
   a sensible floor and the wrapper scrolls, which is what .table-wrap's
   overflow-x was always for. */
@media (max-width: 900px), (hover: none) and (pointer: coarse){
  .module-container, .page-hero, table.data td{ overflow-wrap: break-word; }
}
@media (min-width: 761px){
  table.data{ min-width: 760px; }      /* scroll the wrapper, don't crush the cells */
  .table-wrap{ overflow-x: auto; }
}

/* ---- 2. Money figures were being cut off mid-number ----
   .kpi-value is nowrap + ellipsis inside a 158px track, so a nine-digit GYD
   figure needing ~204px rendered as "GYD 159,3…". On Cashflow at 1280px every
   headline number was unreadable — the owner reading a number missing its
   last digits is worse than no number at all. Give the track room, and where
   there genuinely is none, shrink the type rather than silently truncate. */
.kpi-grid{ grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); }
.kpi-strip{ grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); }
/* break-word split money MID-NUMBER ("122,605,00|0") — worse than either
   truncation or small type. The number now stays on one line and scales with
   its own TILE (cqw), not the viewport; tabular digits keep columns steady.
   Browsers without container units drop only the font-size and may spill a
   few px at the very worst — never a broken figure. */
.kpi-card, .kpi-mini{ container-type: inline-size; }
/* body.dash-overview variants in style.css carry (0,3,0) specificity, so the
   body-scoped selectors here are load-bearing — without them the fixed
   1.6rem wins and a long GYD figure overflows narrow tiles. */
.kpi-card .kpi-value, .kpi-mini .km-value,
body.dash-overview .kpi-mini .km-value{
  white-space: nowrap;
  overflow-wrap: normal;
  font-variant-numeric: tabular-nums;
  font-size: clamp(0.9rem, 10cqw, 1.5rem);
}
@media (max-width: 760px){
  .kpi-grid, .kpi-strip{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpi-card .kpi-value, .kpi-mini .km-value,
  body.dash-overview .kpi-mini .km-value{ font-size: clamp(0.9rem, 10cqw, 1.3rem); }
}

/* ---- 3. Real actions were being hidden by source order ----
   `.page-hero .page-actions .btn:not(:first-of-type){ display:none }` removed
   every button after the first, whatever it did. On Payroll that deleted
   "Next week", "+ Labour entry" and "All payslips" while keeping "‹ Prev", so
   a clerk could step backwards through the year and never forwards. On
   Tenders it removed four of five.

   Keep anything that is a primary/accent action or explicitly marked
   essential; hide only the genuinely desk-bound extras. */
@media (max-width: 760px){
  .page-hero .page-actions .btn:not(:first-of-type){ display: inline-flex; }
  .page-hero .page-actions .btn.desk-only{ display: none; }
}

/* ---- 4. Single actions became full-width orange bars ----
   flex:1 1 auto in the 900px block stretched one button across the whole
   navy header — it read as a form submit, not a page action. */
@media (max-width: 900px), (hover: none) and (pointer: coarse){
  .page-hero .btn{ flex: 0 0 auto; justify-content: center; max-width: 100%; }
  .page-hero .page-actions{ width: 100%; justify-content: flex-end; }
}

/* ---- 5. Row actions floated out of their row ----
   .row-actions is display:flex, which takes the cell out of the table row
   box: its bottom border painted partway up the row as a stray line, and on
   tall rows the icons appeared to belong to the row above. */
table.data td.row-actions{
  display: table-cell;
  vertical-align: middle;
  white-space: nowrap;
  text-align: right;
}
table.data td.row-actions > *{ display: inline-flex; vertical-align: middle; }
table.data td.row-actions .icon-btn + .icon-btn,
table.data td.row-actions .btn + .btn{ margin-left: 6px; }

/* Keep the actions reachable at desktop widths, where the table scrolls and
   the last column sat entirely off-screen behind an invisible scrollbar. */
@media (min-width: 901px){
  table.data td.row-actions, table.data th:last-child{
    position: sticky; right: 0;
    background: var(--m-surface);
    box-shadow: -6px 0 8px -6px rgba(14,27,46,.16);
  }
}

/* ---- 6. The quick-add button hid behind the bottom tab bar ----
   Only a 3px sliver showed above the bar, and tapping it hit the tab bar. */
@media (max-width: 760px){
  .fab{ bottom: calc(74px + env(safe-area-inset-bottom, 0px)); z-index: 95; }
  .fab-sheet{ bottom: calc(128px + env(safe-area-inset-bottom, 0px)); z-index: 95; }
}

/* ---- 7. Scrolling tab strips gave no sign they scroll ----
   More than half the Finance tabs sat off-screen with no fade or cut-off tab,
   so Cashflow and Approvals looked simply absent. */
.sub-nav{
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
          mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
}
.sub-nav-tab{ min-height: 44px; display: inline-flex; align-items: center; }

/* ---- 8. Currency was set in two different faces ----
   Approval cards used a condensed display face with proportional figures
   while every other amount used Inter with tabular figures, so the same
   money looked like two different systems on one page. */
.appr-card .amt{
  font-family: 'Inter', system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
}

/* ---- 9. Filter controls were all different sizes ----
   One filter would sit alone on a second row stretched across the page. */
.filters .form-row{ flex: 0 1 220px; min-width: 176px; }
@media (max-width: 560px){ .filters .form-row{ flex: 1 1 100%; } }

/* Field labels on approval cards, replacing the folder/person emoji. */
.appr-card .meta .meta-k{
  display: inline-block;
  min-width: 96px;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--m-ink-3);
}

/* ---- 10. Identifiers, dates and money must not break mid-way ----
   With cells free to wrap anywhere, an invoice number came out as
   "INV-2026-0" / "008" and a date as "2026-08-" / "12": the cell had 60px for
   something needing 120px. Prose is the only thing that should wrap. Money,
   quantities, dates and reference codes stay whole and the wrapper scrolls —
   which is what a data table is supposed to do. */
table.data td.cell-num, table.data th.cell-num,
table.data td:first-child, table.data th:first-child,
table.data td.nowrap{
  white-space: nowrap;
}
/* Description-style columns keep wrapping so rows do not run away. */
table.data td.wrap, table.data td[data-wrap]{ white-space: normal; }

/* ---- 10b. Table cells do not break words at all ----
   Guarding "first column and money" was still leaving cert numbers, dates and
   project names snapped in half ("IPC-" / "01", "2026-06-" / "03",
   "Rehabilita" / "tion"), because which column holds an identifier differs per
   table and cannot be enumerated.

   So: no word-breaking in table cells, full stop. If a word will not fit, the
   column takes the width it needs and .table-wrap scrolls — which is the point
   of a scroll wrapper and how every data table should behave. The rule this
   replaces existed to stop long strings widening the PAGE; the wrapper already
   does that without mangling the words. Prose outside tables still wraps. */
table.data td, table.data th{
  overflow-wrap: normal;
  word-break: normal;
  hyphens: none;
}
@media (max-width: 900px), (hover: none) and (pointer: coarse){
  table.data td, table.data th{ overflow-wrap: normal; }
}
/* Only genuinely long prose columns may wrap, and only on words. */
table.data td.wrap, table.data td[data-wrap]{
  white-space: normal;
  overflow-wrap: break-word;
}

/* ---- 11. The Calendar on a phone (pairs with v78 in script.js) ----
   At 375px a month cell measured 49.3px, leaving an event chip 32.3px:
   the whole grid read "S…", "P…", "T…", "O…". Seven columns will never
   fit a phone, so below 560px the calendar OPENS in List view — that is
   done in script.js. This is the other half: making both views behave
   once you are down there. Breakpoint matches CAL_NARROW in v78. */
@media (max-width: 559px){

  /* Month stays reachable from the switcher, and when someone picks it
     deliberately it should be a real calendar, not seven crushed strips.
     It keeps its true column widths and scrolls inside its own box —
     the PAGE still does not scroll sideways, which is the rule that
     matters. 640px gives ~91px a column instead of 49px, so a chip
     shows about twelve characters instead of one, and the MON/TUE/WED
     header row stops being cramped. */
  .cal-grid{
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
  }
  /* Both children need the same floor or the header scrolls out of step
     with the days under it. */
  .cal-week-head,
  .cal-month{ min-width: 640px; }

  /* List view is what a phone actually gets, so give it the width.
     The desktop layout is a 80px date column, which is narrower than
     "2026-08-13" and was breaking the date across two lines while
     squeezing the title into 118px and four lines. Date and countdown
     move onto their own line above the title, which then has the full
     width of the card. */
  .cal-list-item{
    grid-template-columns: 18px 1fr auto;
    grid-template-areas:
      "dot date  badge"
      "dot title title";
    gap: 2px 10px;
    padding: 12px 14px;
    align-items: start;
  }
  .cal-list-item .date{ grid-area: date; font-size: .78rem; }
  .cal-list-item .cal-event{ grid-area: dot; margin-top: 3px; }
  .cal-list-item strong{ grid-area: title; line-height: 1.35; }
  .cal-list-item .badge{ grid-area: badge; justify-self: end; }
}

/* ============================================================
   Design round 2 — density & de-clutter
   Work pages open onto the work: tighter tables and cards, and a
   shared fold component (details.zc-fold) that tucks analytics
   behind a remembered toggle.
============================================================ */
table.data th{ padding: 9px 12px; }
table.data td{ padding: 8px 12px; }
/* Long project names/notes were wrapping to 4+ lines and driving 100px rows.
   Two lines then ellipsis; the full text stays in the cell's title tooltip. */
table.data td small{
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.page-head{ margin-bottom: 12px; }
.kpi-strip, .kpi-grid{ margin-bottom: 10px; }
.filters{ row-gap: 8px; }

details.zc-fold{
  border: 1px solid var(--m-line); border-radius: 12px;
  background: var(--m-surface); margin-top: 14px;
}
details.zc-fold > summary{
  cursor: pointer; padding: 13px 16px; font-weight: 700;
  color: var(--m-ink-2); list-style: none;
  display: flex; align-items: center; gap: 8px; user-select: none;
}
details.zc-fold > summary::before{ content: '▸'; transition: transform .15s; }
details.zc-fold[open] > summary::before{ transform: rotate(90deg); }
details.zc-fold > summary::-webkit-details-marker{ display: none; }
details.zc-fold > .zc-fold-body{ padding: 0 16px 16px; }
details.zc-fold > .zc-fold-body > *{ margin-top: 12px; }

/* Long queues/logs scroll inside their card instead of stretching the page */
.zc-scroll-card{ max-height: 460px; overflow-y: auto; }

/* ---- v85: notification bell + panel ---- */
.zc-bell{
  position: relative; border: 1px solid var(--m-line); background: var(--m-surface);
  border-radius: 50%; width: 38px; height: 38px; cursor: pointer; font-size: 1rem;
  display: inline-flex; align-items: center; justify-content: center;
}
.zc-bell:hover{ background: var(--m-line-soft); }
.zc-bell-badge{
  position: absolute; top: -4px; right: -4px;
  background: var(--m-risk); color: #fff; font-size: .66rem; font-weight: 800;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
}
.notif-item{
  display: flex; gap: 12px; align-items: flex-start;
  padding: 11px 2px; border-bottom: 1px solid var(--m-line-soft);
}

/* ============================================================
   v90 — Users & Access redesign: cards, not a ledger row.
   Tokens only — no new colours outside the system.
============================================================ */
.user-card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px;}
.user-card{background:var(--m-surface);border:1px solid var(--m-line);border-radius:14px;padding:16px;display:flex;flex-direction:column;gap:12px;box-shadow:0 1px 2px rgba(14,27,46,.05);}
.user-card.is-inactive{opacity:.62;background:var(--m-surface-2);}
.uc-head{display:flex;align-items:center;gap:12px;}
.uc-avatar{width:44px;height:44px;border-radius:50%;background:var(--m-navy);color:var(--m-on-navy);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.05rem;letter-spacing:.02em;flex:none;}
.uc-avatar.tier-top{background:var(--m-accent);}
.uc-id{min-width:0;}
.uc-name{font-weight:800;color:var(--m-ink);font-size:1.02rem;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.uc-sub{color:var(--m-ink-3);font-size:.82rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.uc-badges{display:flex;flex-wrap:wrap;gap:6px;}
.uc-role{font-size:.72rem;font-weight:800;letter-spacing:.04em;text-transform:uppercase;padding:3px 9px;border-radius:99px;border:1px solid var(--m-line);color:var(--m-ink-2);background:var(--m-surface-2);}
.uc-role.tier-top{background:var(--m-accent-wash);border-color:var(--m-accent);color:var(--m-accent-ink);}
.uc-role.tier-mgmt{background:#E8EEF7;border-color:#B9C6D6;color:#17293F;}
.uc-chip{font-size:.74rem;font-weight:700;padding:3px 9px;border-radius:99px;}
.uc-chip.ok{background:var(--m-ok-wash);color:var(--m-ok);border:1px solid var(--m-ok-line);}
.uc-chip.warn{background:var(--m-warn-wash);color:var(--m-warn);border:1px solid var(--m-warn-line);}
.uc-chip.risk{background:var(--m-risk-wash);color:var(--m-risk);border:1px solid var(--m-risk-line);}
.uc-chip.quiet{background:var(--m-surface-2);color:var(--m-ink-3);border:1px solid var(--m-line-soft);}
.uc-access{font-size:.85rem;color:var(--m-ink-2);line-height:1.5;border-top:1px solid var(--m-line-soft);padding-top:10px;}
.uc-access strong{color:var(--m-ink);}
.uc-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:auto;border-top:1px solid var(--m-line-soft);padding-top:10px;}
.uc-last{font-size:.76rem;color:var(--m-ink-3);}
.uc-actions{display:flex;gap:6px;}
.uc-btn{border:1px solid var(--m-line);background:var(--m-surface);color:var(--m-ink-2);border-radius:8px;padding:6px 10px;font-size:.8rem;font-weight:700;cursor:pointer;}
.uc-btn:hover{border-color:var(--m-navy);color:var(--m-ink);}
.uc-btn.danger:hover{border-color:var(--m-risk);color:var(--m-risk);background:var(--m-risk-wash);}
/* grouped page picker in the user form */
.pg-group{border:1px solid var(--m-line-soft);border-radius:10px;margin-bottom:8px;overflow:hidden;background:var(--m-surface);}
.pg-group-head{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--m-surface-2);border-bottom:1px solid var(--m-line-soft);font-weight:800;font-size:.82rem;color:var(--m-ink-2);text-transform:uppercase;letter-spacing:.04em;cursor:pointer;user-select:none;}
.pg-group-head .pg-count{margin-left:auto;font-weight:700;color:var(--m-ink-3);font-size:.76rem;text-transform:none;letter-spacing:0;}
.pg-group-body{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:4px 10px;padding:10px 12px;}
.pg-group-body label{display:flex;align-items:center;gap:6px;font-size:.85rem;color:var(--m-ink);font-weight:500;text-transform:none;letter-spacing:0;}
@media (max-width:640px){ .user-card-grid{grid-template-columns:1fr;} }

/* ============================================================
   v99 — Colour on the staff home carries meaning, not decoration.

   The money tiles take the SAME colour as their segment in the
   "Where the month went" bar, so the eye links a tile to its slice
   without a legend. The attention tiles are coloured by severity
   instead: red only when something is actually overdue, amber when
   it is waiting, plain when there is nothing to do — so a glance
   at the row tells you whether the day is clear.

   Left edge + a wash, never a saturated fill: the figure itself
   must stay near-black for contrast (the value keeps #0f172a).
============================================================ */
.kpi-mini[class*="acc-"]{ border-left-width: 3px; border-left-style: solid; }
.kpi-mini[class*="acc-"] .km-label{ color: var(--m-ink-2); }

/* Cost categories — matched to the split bar in "Where the month went" */
.kpi-mini.acc-labour    { background:#FFF8EF; border-color:#FBE3C4; border-left-color:#F39200; }
.kpi-mini.acc-materials { background:#F2F6FB; border-color:#D4E1EF; border-left-color:#0A3D62; }
.kpi-mini.acc-fuel      { background:#F1FBF4; border-color:#CBEBD6; border-left-color:#16A34A; }
.kpi-mini.acc-misc      { background:#FAF5FF; border-color:#E7D5FB; border-left-color:#A855F7; }

/* The month's total — navy, the same weight the brand gives a summary */
.kpi-mini.acc-total     { background:#F4F6FA; border-color:#DFE5ED; border-left-color:#0E1B2E; }
.kpi-mini.acc-total .km-value{ color:#0E1B2E; }

/* Direction of money: out is red, in is green */
.kpi-mini.acc-out       { background:#FDF3F2; border-color:#F0C9C5; border-left-color:#A01B14; }
.kpi-mini.acc-out .km-value{ color:#A01B14; }
.kpi-mini.acc-in        { background:#F0F8F3; border-color:#C3E3D2; border-left-color:#0B6B43; }
.kpi-mini.acc-in .km-value{ color:#0B6B43; }

/* Severity, for the attention row */
.kpi-mini.acc-urgent    { background:#FDF3F2; border-color:#F0C9C5; border-left-color:#A01B14; }
.kpi-mini.acc-waiting   { background:#FDF8EE; border-color:#EDDCB9; border-left-color:#8A5210; }
.kpi-mini.acc-steady    { background:#F3F7FC; border-color:#D3E2F2; border-left-color:#2F6FB5; }
.kpi-mini.acc-clear     { background:#FFFFFF; border-left-color:#CBD5E1; }

/* The tile is a link; say so on hover without moving the layout. */
.kpi-mini[onclick]{ cursor:pointer; }
.kpi-mini[onclick]:hover{ box-shadow:0 4px 14px rgba(14,27,46,.10); }
