/* Tamatem Ops — the mockup's stylesheet, ported verbatim.
 *
 * This file is the design. It came from docs/mockup.html, which the team
 * reviewed screen by screen, so it is copied rather than reinterpreted: the
 * tokens, the spacing scale, the type scale, the component classes and the
 * RTL rules are all the ones that were signed off.
 *
 * If a screen looks wrong, the fix is almost always to use the right class
 * from here, not to add a new rule. Additions specific to the real app —
 * things the prototype faked in JS — are at the bottom, under "Beyond the
 * mockup", so the ported part stays diffable against the original.
 */

  :root{
    --bg:#f5f6f8; --panel:#ffffff; --border:#e3e6ea; --border-strong:#a8b0ba;
    --text:#151a21; --muted:#5b6470; --faint:#6a7280;
    --accent:#4f46e5; --accent-soft:#eef0fe;
    /* the accent's channels, so a computed alpha can be built from the token
       rather than from a second copy of the hex */
    --accent-rgb:79 70 229;
    --ok:#116932; --ok-soft:#e8f6ec;
    --warn:#8a4009; --warn-soft:#fdf3e3;
    --danger:#b42318; --danger-soft:#fdecea;
    --info:#0b5c72; --info-soft:#e6f5f8;
    --radius:8px;
    --shadow:0 1px 2px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.1);
    --shadow-lg:0 12px 32px rgba(16,24,40,.16);

    /* spacing scale */
    --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
    /* type scale */
    --t-xs:11px; --t-sm:12.5px; --t-md:13.5px; --t-lg:16px; --t-xl:19px; --t-2xl:24px;
    --focus:#1d4ed8;
  }
  *{box-sizing:border-box}
  html,body{height:100%}
  body{
    margin:0; background:var(--bg); color:var(--text);
    font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
    -webkit-font-smoothing:antialiased;
  }
  button{font:inherit; cursor:pointer}
  input,select,textarea{font:inherit; color:inherit}
  .hidden{display:none !important}


  /* ---------- direction ---------- */
  html[dir="rtl"] body{ direction:rtl }
  html[dir="rtl"] aside{ order:2 }
  html[dir="rtl"] main{ order:1 }
  html[dir="rtl"] #drawer{ right:auto; left:0; transform:translateX(-100%) }
  html[dir="rtl"] #drawer.open{ transform:translateX(0) }
  html[dir="rtl"] .nav-item{ text-align:right }
  html[dir="rtl"] th, html[dir="rtl"] td{ text-align:right }
  html[dir="rtl"] .num{ text-align:left }
  html[dir="rtl"] .search span{ inset-inline-start:9px; inset-inline-end:auto }
  bdi{ unicode-bidi:isolate }
  .mono, .ltr{ direction:ltr; unicode-bidi:isolate; text-align:start }
  .num{ direction:ltr; unicode-bidi:isolate }
  .avatar-sm{ margin-inline-end:var(--s2); margin-right:0 }
  .search span{ inset-inline-start:9px; left:auto }
  .search input{ padding-inline:30px var(--s3) }
  .chip{ margin-inline-start:5px; margin-left:0 }

  /* ---------- focus ---------- */
  a:focus-visible, button:focus-visible, input:focus-visible,
  select:focus-visible, textarea:focus-visible, tr:focus-visible, [tabindex]:focus-visible{
    outline:2px solid var(--focus); outline-offset:2px; border-radius:4px;
  }
  tbody tr:focus-visible{ outline-offset:-2px; background:var(--accent-soft) }
  .skip-link{ position:absolute; inset-inline-start:-9999px; top:0; z-index:200;
    background:#fff; padding:var(--s2) var(--s3); border:1px solid var(--border-strong) }
  .skip-link:focus{ inset-inline-start:0 }

  /* status carries a glyph, not colour alone */
  .badge::before{ content:attr(data-mark); margin-inline-end:4px; font-weight:700 }

  /* ---------- density ---------- */
  body.compact .col-2{ display:none }
  .density{ display:flex; border:1px solid var(--border-strong); border-radius:7px; overflow:hidden }
  .density button{ border:0; background:#fff; padding:5px 9px; font-size:var(--t-sm); color:var(--muted) }
  .density button.on{ background:var(--accent); color:#fff }

  /* min-width:0 matters as much as the overflow does. A grid or flex item will
     not shrink below its own content by default, so without this the widest
     table inside a panel makes the panel, its grid column and the whole page
     wider than the screen — and the scroll container never gets used, because
     nothing ever overflows it. */
  .tablewrap{ overflow-x:auto; -webkit-overflow-scrolling:touch; min-width:0 }
  thead th{ position:sticky; top:0; z-index:2 }

  /* The breakpoints themselves are at the very end of this file, after every
     component rule. See the note there — putting them here is what broke them. */
  #navToggle{ display:none; align-items:center; justify-content:center; width:32px; height:32px;
    border:1px solid var(--border-strong); border-radius:7px; background:#fff }

  @media (prefers-reduced-motion:reduce){ *{ transition:none !important; animation:none !important } }

  /* ---------- Sign in ---------- */
  #signin{
    position:fixed; inset:0; background:linear-gradient(160deg,#1e1b3a,#2d2a52 55%,#1a2a44);
    display:flex; align-items:center; justify-content:center; z-index:100;
  }
  .signin-card{
    width:380px; background:#fff; border-radius:14px; padding:36px 32px;
    box-shadow:0 24px 60px rgba(0,0,0,.35); text-align:center;
  }
  .signin-logo{
    width:46px;height:46px;border-radius:11px;background:var(--accent);color:#fff;
    display:flex;align-items:center;justify-content:center;font-weight:700;font-size:19px;
    margin:0 auto 16px;
  }
  .signin-card h1{font-size:19px;margin:0 0 6px}
  .signin-card p{color:var(--muted);margin:0 0 26px;font-size:13px}
  .gbtn{
    width:100%; display:flex; align-items:center; justify-content:center; gap:10px;
    padding:11px 14px; background:#fff; border:1px solid var(--border-strong);
    border-radius:8px; font-weight:500; transition:background .15s;
  }
  .gbtn:hover{background:#f7f8fa}
  .signin-note{margin-top:20px;font-size:11.5px;color:var(--faint);line-height:1.6}

  /* ---------- Shell ---------- */
  #app{display:flex; min-height:100vh}
  aside{
    width:224px; flex:none; background:#161b25; color:#c3cad5;
    display:flex; flex-direction:column; position:sticky; top:0; height:100vh;
  }
  .brand{display:flex;align-items:center;gap:10px;padding:18px 18px 16px;color:#fff}
  .brand-mark{width:28px;height:28px;border-radius:7px;background:var(--accent);
    display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13px;color:#fff}
  .brand b{font-size:13.5px;font-weight:600;letter-spacing:.2px}
  .brand small{display:block;font-size:10.5px;color:#7d8899;font-weight:400}
  nav{padding:6px 10px; flex:1; overflow:auto}
  .nav-label{font-size:10px;text-transform:uppercase;letter-spacing:.9px;color:#69737f;
    padding:14px 8px 6px;font-weight:600}
  .nav-item{
    display:flex;align-items:center;gap:10px;width:100%;text-align:left;
    padding:8px 10px;border:0;background:transparent;color:#c3cad5;border-radius:6px;
    font-size:13.5px;margin-bottom:1px;
  }
  .nav-item:hover{background:#212836;color:#fff}
  .nav-item.active{background:var(--accent);color:#fff;font-weight:500}
  .nav-item .ico{width:16px;text-align:center;opacity:.9;font-size:13px}
  .nav-item .count{margin-left:auto;font-size:11px;background:#2a3140;padding:1px 6px;border-radius:9px;color:#9aa5b4}
  .nav-item.active .count{background:rgba(255,255,255,.22);color:#fff}
  .sidebar-foot{padding:12px;border-top:1px solid #252c39;font-size:11px;color:#69737f}

  main{flex:1; min-width:0; display:flex; flex-direction:column}
  header.topbar{
    background:var(--panel); border-bottom:1px solid var(--border);
    padding:0 22px; height:56px; display:flex; align-items:center; gap:14px;
    position:sticky; top:0; z-index:20;
  }
  .topbar h2{font-size:15px;margin:0;font-weight:600}
  .topbar .crumb{color:var(--faint);font-size:12.5px}
  .spacer{flex:1}
  .role-wrap{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--muted)}
  .role-wrap select{
    padding:5px 9px;border:1px solid var(--border-strong);border-radius:6px;background:#fff;font-size:12.5px;
  }
  .avatar{
    width:30px;height:30px;border-radius:50%;background:#dfe3ea;color:#4b5563;
    display:flex;align-items:center;justify-content:center;font-size:11.5px;font-weight:600;
  }
  .content{padding:22px; max-width:1500px; width:100%}

  /* ---------- Bits ---------- */
  .page-head{display:flex;align-items:flex-start;gap:12px;margin-bottom:18px}
  .page-head h3{margin:0 0 3px;font-size:19px;font-weight:600}
  .page-head p{margin:0;color:var(--muted);font-size:13px}
  .btn{
    padding:7px 13px;border-radius:7px;border:1px solid var(--border-strong);
    background:#fff;font-size:13px;font-weight:500;display:inline-flex;align-items:center;gap:6px;
  }
  .btn:hover:not(:disabled){background:#f7f8fa}
  .btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
  .btn.primary:hover:not(:disabled){background:#4338ca}
  .btn.danger{color:var(--danger);border-color:#f0c4bf}
  .btn.danger:hover:not(:disabled){background:var(--danger-soft)}
  .btn:disabled{opacity:.45;cursor:not-allowed}
  .btn.sm{padding:4px 9px;font-size:12px}

  /* htmx toggles the htmx-request class on the request's indicator target for
     as long as the request is in flight — hidden the rest of the time. */
  .htmx-indicator{opacity:0;font-size:12.5px;color:var(--muted);transition:opacity 120ms ease-in}
  .htmx-request.htmx-indicator,.htmx-request .htmx-indicator{opacity:1}

  .panel{background:var(--panel);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow)}
  .panel-head{padding:13px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px}
  .panel-head h4{margin:0;font-size:13.5px;font-weight:600}
  .panel-head .sub{font-size:12px;color:var(--muted)}

  .kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:16px}
  .kpi{background:var(--panel);border:1px solid var(--border);border-radius:var(--radius);padding:15px 16px;box-shadow:var(--shadow)}
  .kpi .label{font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;font-weight:600}
  .kpi .value{font-size:24px;font-weight:650;margin:7px 0 3px;letter-spacing:-.4px}
  .kpi .delta{font-size:12px;color:var(--muted)}
  .delta.up{color:var(--ok)} .delta.down{color:var(--danger)}

  .grid2{display:grid;grid-template-columns:1.55fr 1fr;gap:14px;margin-bottom:16px}
  /* Same reason as .tablewrap above: let a panel stop at its track width and
     hand any overflow to the scroll container inside it. */
  .grid2>*, .grid2b>*, .grid3>*{ min-width:0 }
  /* Panels in a two-up row are already stretched to the taller of the pair by
     the grid. This passes that height down so a chart grows into it instead of
     sitting at its minimum above an empty half-panel. */
  .grid2>.panel{display:flex;flex-direction:column}
  .grid2>.panel>.bars{flex:1}
  /* Two ranked lists side by side rarely have the same number of rows. Stretched
     to a common height, the shorter one is a card with a hole in it; sized to its
     own content, it is just a shorter card. The gap belongs outside the panel. */
  .grid2b{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}

  table{width:100%;border-collapse:collapse}
  th{
    text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);
    font-weight:600;padding:9px 12px;border-bottom:1px solid var(--border);background:#fbfcfd;
    white-space:nowrap;
  }
  td{padding:10px 12px;border-bottom:1px solid #eef0f3;font-size:13px;white-space:nowrap}
  tbody tr:hover{background:#fafbfd;cursor:pointer}
  tbody tr:last-child td{border-bottom:0}
  .num{text-align:right;font-variant-numeric:tabular-nums}
  .mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--muted)}
  .truncate{max-width:190px;overflow:hidden;text-overflow:ellipsis;display:inline-block;vertical-align:bottom}

  .badge{display:inline-block;padding:2px 8px;border-radius:20px;font-size:11.5px;font-weight:600;white-space:nowrap}
  .b-ok{background:var(--ok-soft);color:var(--ok)}
  .b-warn{background:var(--warn-soft);color:var(--warn)}
  .b-danger{background:var(--danger-soft);color:var(--danger)}
  .b-info{background:var(--info-soft);color:var(--info)}
  .b-muted{background:#eef0f3;color:var(--muted)}
  .b-accent{background:var(--accent-soft);color:var(--accent)}

  .toolbar{display:flex;gap:8px;align-items:center;padding:11px 14px;border-bottom:1px solid var(--border);flex-wrap:wrap}
  .search{position:relative;flex:1;min-width:180px;max-width:320px}
  .search input{width:100%;padding:7px 10px 7px 30px;border:1px solid var(--border-strong);border-radius:7px;background:#fff}
  .search span{position:absolute;left:9px;top:50%;transform:translateY(-50%);color:var(--faint);font-size:13px}
  .toolbar select{padding:6px 9px;border:1px solid var(--border-strong);border-radius:7px;background:#fff;font-size:13px}

  .avatar-sm{width:24px;height:24px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
    font-size:10px;font-weight:600;color:#fff;margin-right:8px;vertical-align:middle}
  .who{display:flex;align-items:center}

  .empty{padding:40px;text-align:center;color:var(--muted);font-size:13px}
  .foot-note{padding:10px 14px;border-top:1px solid var(--border);font-size:12px;color:var(--muted)}

  /* ---------- Drawer ---------- */
  #scrim{position:fixed;inset:0;background:rgba(16,24,40,.42);z-index:40;opacity:0;transition:opacity .18s}
  /* Shown the instant a drawer is requested, not once it arrives — the fetch
     for a fresh drawer is not instant, and a click with no feedback reads as
     broken. */
  #drawerLoading{
    position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:51;
    display:flex;flex-direction:column;align-items:center;gap:10px;color:#fff;font-size:13px;
  }
  #drawerLoadingRing{
    width:34px;height:34px;border-radius:50%;border:3px solid rgba(255,255,255,.35);
    border-top-color:#fff;animation:drawer-spin .7s linear infinite;
  }
  @keyframes drawer-spin{to{transform:rotate(360deg)}}
  /* Navigation progress. A page render is a round trip to a database on the
     other side of a WAN link — without this, a click looks like nothing
     happened for about a second. */
  #navProgress{
    position:fixed;inset-block-start:0;inset-inline-start:0;height:3px;width:0;z-index:200;
    background:var(--accent);border-end-end-radius:3px;opacity:0;
    transition:width .18s ease,opacity .2s ease;pointer-events:none;
  }
  #navProgress.run{opacity:1}
  @media (prefers-reduced-motion:reduce){
    #navProgress{transition:none}
    #drawerLoadingRing{animation-duration:1.6s}
  }
  #drawer{
    position:fixed;top:0;right:0;height:100%;width:560px;max-width:96vw;background:#fff;z-index:50;
    box-shadow:var(--shadow-lg);display:flex;flex-direction:column;transform:translateX(100%);transition:transform .22s ease;
  }
  #drawer.open{transform:translateX(0)}
  .drawer-head{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;align-items:flex-start;gap:10px}
  .drawer-head h3{margin:0 0 3px;font-size:16px}
  .drawer-head .sub{font-size:12.5px;color:var(--muted)}
  .x{border:0;background:transparent;font-size:20px;color:var(--faint);line-height:1;padding:0 4px}
  .drawer-body{padding:18px 20px;overflow:auto;flex:1}
  .drawer-foot{padding:13px 20px;border-top:1px solid var(--border);display:flex;gap:8px;align-items:center;background:#fbfcfd}

  .form-grid{display:grid;grid-template-columns:1fr 1fr;gap:13px}
  .field{display:flex;flex-direction:column;gap:4px}
  .field.full{grid-column:1/-1}
  .field label{font-size:11.5px;font-weight:600;color:var(--muted);letter-spacing:.2px}
  .field label .col{font-family:ui-monospace,Menlo,monospace;font-weight:400;color:var(--faint);font-size:10.5px}
  .field input,.field select,.field textarea{
    padding:7px 9px;border:1px solid var(--border-strong);border-radius:6px;background:#fff;width:100%;
  }
  .field input:focus,.field select:focus,.field textarea:focus{outline:2px solid var(--accent-soft);border-color:var(--accent)}
  .field input:read-only{background:#f4f5f7;color:var(--muted)}
  /* Searchable dropdown. A native select can't contain a text input, so the
     list is divs and a hidden input carries the value the form submits. */
  .combo{position:relative}
  .combo-trigger{
    width:100%;text-align:start;padding:7px 28px 7px 10px;border:1px solid var(--border-strong);
    border-radius:7px;background:#fff;font:inherit;font-size:var(--t-sm);color:var(--text);
    cursor:pointer;display:block;
  }
  .combo-trigger::after{
    content:"⌄";position:absolute;inset-inline-end:10px;inset-block-start:5px;color:var(--muted);
    pointer-events:none;
  }
  .combo-trigger:focus{outline:2px solid var(--accent-soft);border-color:var(--accent)}
  .combo-trigger[aria-expanded="true"]{border-color:var(--accent)}
  .combo-trigger:disabled{background:#f4f5f7;color:var(--muted);cursor:not-allowed}
  .combo-value[data-empty]{color:var(--muted)}
  .combo-panel{
    position:absolute;inset-inline:0;inset-block-start:calc(100% + 4px);z-index:60;background:#fff;
    border:1px solid var(--border-strong);border-radius:8px;box-shadow:var(--shadow-lg);padding:8px;
  }
  .combo-filter{width:100%;margin-bottom:6px}
  .combo-list{max-height:230px;overflow-y:auto}
  .combo-opt{padding:7px 9px;border-radius:6px;cursor:pointer;font-size:var(--t-sm)}
  .combo-opt:hover{background:var(--accent-soft)}
  .combo-opt.on{background:var(--accent-soft);font-weight:600}
  .combo-opt.empty{color:var(--muted);cursor:default}
  .combo-opt.empty:hover{background:transparent}

  /* multi-select: the chosen rows sit above the trigger, each removable */
  .combo-chips{display:flex;flex-wrap:wrap;gap:5px}
  .combo-chips:not(:empty){margin-block-end:6px}
  .chip{display:inline-flex;align-items:center;gap:5px;max-inline-size:100%;
    padding:3px 5px 3px 9px;border:1px solid var(--border);border-radius:999px;
    background:var(--accent-soft);font-size:12px;line-height:1.5}
  .chip bdi{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .chip-x{border:0;background:transparent;cursor:pointer;padding:0 3px;
    color:var(--muted);font-size:14px;line-height:1;border-radius:50%}
  .chip-x:hover{background:var(--danger-soft);color:var(--danger)}
  .section-title{font-size:11px;text-transform:uppercase;letter-spacing:.7px;color:var(--faint);
    font-weight:700;margin:22px 0 11px;padding-bottom:6px;border-bottom:1px solid var(--border)}
  .section-title:first-child{margin-top:0}
  .hint{font-size:11.5px;color:var(--faint)}

  /* validation */
  .err{font-size:11.5px;color:var(--faint);min-height:1px;line-height:1.45}
  .err.bad{color:var(--danger);font-weight:500}
  .err.warn{color:var(--warn)}
  .req{color:var(--danger);font-weight:700}
  .field.invalid input,.field.invalid select,.field.invalid textarea,.field.invalid .combo-input{
    border-color:#e5a29a; background:#fffbfa;
  }
  .field.invalid input:focus,.field.invalid .combo-input:focus{outline:2px solid var(--danger-soft)}
  .field.warned input,.field.warned select,.field.warned .combo-input{border-color:#e8c98d}
  .errbar{
    background:var(--danger-soft);border:1px solid #f2c4bd;color:#8a2b20;
    padding:9px 12px;border-radius:7px;font-size:12.5px;margin-bottom:16px;line-height:1.6;
  }
  .errbar b{font-family:ui-monospace,Menlo,monospace}
  .errbar a{color:#8a2b20}
  .drawer-foot .rule-note{font-size:11.5px;color:var(--faint);margin-left:auto;text-align:right}

  /* finance: bars, balance summary, allocations */
  .mini-bar{display:inline-block;width:64px;height:6px;background:#eef0f3;border-radius:3px;overflow:hidden;vertical-align:middle}
  .mini-bar i{display:block;height:100%;background:var(--accent);border-radius:3px}
  .mini-bar i.ok{background:var(--ok)} .mini-bar i.warn{background:var(--warn)} .mini-bar i.danger{background:var(--danger)}

  .bal{border:1px solid var(--border);border-radius:9px;overflow:hidden;background:#fbfcfd}
  .bal-head{display:flex;align-items:baseline;gap:10px;padding:13px 15px;background:#fff;border-bottom:1px solid var(--border)}
  .bal-head .big{font-size:22px;font-weight:650;letter-spacing:-.4px}
  .bal-head .cur{font-size:12px;color:var(--muted)}
  .bal-rows{padding:4px 15px 12px}
  .bal-row{display:grid;grid-template-columns:118px 1fr 96px;gap:10px;align-items:center;padding:7px 0;font-size:12.5px}
  .bal-row .lb{color:var(--muted)}
  .bal-row .vl{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
  .bal-row .track{height:7px;background:#eaedf1;border-radius:4px;overflow:hidden}
  .bal-row .track i{display:block;height:100%;border-radius:4px}
  .bal-foot{display:flex;gap:8px;align-items:center;padding:11px 15px;border-top:1px solid var(--border);background:#fff;font-size:12.5px}
  .bal-foot .big{font-size:16px;font-weight:650}
  .fill-alloc{background:var(--accent)} .fill-settle{background:var(--ok)}
  .fill-open{background:var(--warn)} .fill-none{background:#cdd2d9}

  .alloc-row{display:grid;grid-template-columns:1fr 118px 92px 30px;gap:9px;align-items:center;
    padding:8px 0;border-bottom:1px solid #eef0f3;font-size:12.5px}
  .alloc-row input,.alloc-row select{padding:6px 8px;border:1px solid var(--border-strong);border-radius:6px;width:100%}
  .alloc-row .pct{text-align:right;color:var(--muted);font-variant-numeric:tabular-nums}
  .alloc-row .del{border:0;background:transparent;color:var(--faint);font-size:16px;line-height:1}
  .alloc-row .del:hover{color:var(--danger)}
  .alloc-total{display:flex;align-items:center;gap:10px;padding:10px 0 0;font-size:12.5px;font-weight:600}
  .alloc-total .spacer{flex:1}
  .alloc-warn{color:var(--danger)} .alloc-ok{color:var(--ok)}
  .ledger td{padding:7px 0;font-size:12.5px;border-bottom:1px solid #eef0f3}

  /* data model page */
  .erd{background:#fbfcfd;border:1px solid var(--border);border-radius:var(--radius);padding:8px;overflow-x:auto}
  .tbl-card{background:var(--panel);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow);overflow:hidden}
  .tbl-card h5{margin:0;padding:11px 14px;border-bottom:1px solid var(--border);font-size:13px;background:#fbfcfd}
  .tbl-card h5 span{font-weight:400;color:var(--muted);font-size:11.5px}
  .col-row{display:grid;grid-template-columns:1fr auto;gap:8px;padding:6px 14px;border-bottom:1px solid #f2f4f6;font-size:12.5px;align-items:center}
  .col-row:last-child{border-bottom:0}
  .col-row .cn{font-family:ui-monospace,Menlo,monospace}
  .chip{font-size:9.5px;font-weight:700;letter-spacing:.4px;padding:1px 5px;border-radius:3px;margin-left:5px;vertical-align:middle}
  .chip.pk{background:#efe9ff;color:#5b21b6}
  .chip.fk{background:#e6f5f8;color:#0e7490}
  .chip.uq{background:#e8f6ec;color:#15803d}
  .chip.nn{background:#f1f3f5;color:#5c6470}
  .chip.new{background:#fdf3e3;color:#b45309}
  .dtype{color:var(--faint);font-size:11.5px;font-family:ui-monospace,Menlo,monospace}
  pre.ddl{
    margin:0;padding:14px 16px;background:#161b25;color:#d7dee9;font-size:11.5px;line-height:1.65;
    overflow-x:auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  }
  pre.ddl .k{color:#c792ea} pre.ddl .t{color:#89ddff} pre.ddl .c{color:#7d8799;font-style:italic} pre.ddl .s{color:#c3e88d}
  .grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}

  /* combo (searchable relational dropdown) */
  .combo{position:relative}
  .combo-input{width:100%;padding:7px 26px 7px 9px;border:1px solid var(--border-strong);border-radius:6px;background:#fff}
  .combo::after{content:"▾";position:absolute;right:9px;top:29px;color:var(--faint);pointer-events:none;font-size:11px}
  .combo.nolabel::after{top:9px}
  .combo-list{
    position:absolute;top:100%;left:0;right:0;background:#fff;border:1px solid var(--border-strong);
    border-radius:7px;box-shadow:var(--shadow-lg);max-height:230px;overflow:auto;z-index:10;margin-top:3px;
  }
  .combo-opt{padding:7px 10px;display:flex;align-items:center;gap:8px;font-size:13px}
  .combo-opt:hover,.combo-opt.hi{background:var(--accent-soft)}
  .combo-opt .meta{margin-left:auto;font-size:11px;color:var(--muted)}
  .combo-none{padding:10px;color:var(--muted);font-size:12.5px}
  .linked{margin-top:5px;font-size:11.5px;color:var(--muted)}
  .linked a{color:var(--accent);text-decoration:none}

  .kv{display:grid;grid-template-columns:150px 1fr;gap:7px 12px;font-size:13px}
  .kv dt{color:var(--muted);font-size:12px}
  .kv dd{margin:0}

  /* timeline */
  .tl{position:relative;padding-left:20px}
  .tl:before{content:"";position:absolute;left:5px;top:4px;bottom:4px;width:2px;background:var(--border)}
  .tl-item{position:relative;padding:0 0 16px}
  .tl-item:before{content:"";position:absolute;left:-19px;top:5px;width:10px;height:10px;border-radius:50%;
    background:#fff;border:2px solid var(--accent)}
  .tl-item .when{font-size:11.5px;color:var(--faint)}
  .tl-item .what{font-size:13px;margin-top:1px}
  .diff{background:#f7f8fa;border:1px solid var(--border);border-radius:6px;padding:7px 10px;margin-top:6px;font-size:12px}
  .diff .old{color:var(--danger);text-decoration:line-through}
  .diff .new{color:var(--ok);font-weight:600}

  /* charts */
  .bars{display:flex;align-items:stretch;gap:12px;min-height:170px;padding:14px 16px 0}
  .bar-col{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px;min-width:0}
  /*
    The bar is measured against this track, not against the whole column.

    The column also holds the amount above and the month below, so a bar asking
    for 100% of it wanted more room than was left and flexbox shrank it to fit.
    Everything above about three quarters of the peak came out the same height:
    with real data that drew five of eight months identically, and made June's
    $63,798 look the same as January's $50,514. The track takes whatever height
    the labels leave and nothing else measures against it, so a percentage here
    is the percentage that gets drawn.
  */
  .bar-track{flex:1;min-height:0;width:100%;display:flex;align-items:flex-end;justify-content:center}
  .bar{flex:none;width:100%;max-width:56px;background:var(--accent);border-radius:4px 4px 0 0;position:relative;transition:opacity .15s}
  .bar:hover{opacity:.8}
  .bar-lbl{font-size:10.5px;color:var(--muted)}
  .bar-val{font-size:10.5px;color:var(--faint)}
  .split{padding:14px 16px}
  .split-row{display:flex;align-items:center;gap:10px;margin-bottom:11px;font-size:12.5px}
  .split-row .nm{width:88px;flex:none;color:var(--muted)}
  .split-bar{flex:1;height:7px;background:#eef0f3;border-radius:4px;overflow:hidden}
  .split-bar i{display:block;height:100%;background:var(--accent);border-radius:4px}
  .split-row .vl{width:70px;text-align:right;font-variant-numeric:tabular-nums}
  /* share of the total, beside the amount. Muted because it is the second
     reading of the same row, not a competing figure. */
  .split-row .pct{width:44px;text-align:right;color:var(--muted);
                  font-variant-numeric:tabular-nums}

  /* A cell shaded by how big it is. --i is 0..1, set per cell, so one grid of
     numbers can be read as a shape before it is read as numbers. 0.28 was picked
     against the real grid: at 0.16 the scale was too faint to read as one, and
     much past this the body text starts fighting the fill. A heat map you have
     to squint at is worse than a plain table, in either direction. */
  td.heat{background:rgb(var(--accent-rgb) / calc(var(--i, 0) * 0.28))}

  /* import */
  .drop{
    border:2px dashed var(--border-strong);border-radius:10px;padding:34px;text-align:center;
    background:#fbfcfd;color:var(--muted);
  }
  .drop b{color:var(--text)}
  .steps{display:flex;gap:0;margin-bottom:18px}
  .step{flex:1;padding:10px 12px;border-bottom:3px solid var(--border);font-size:12.5px;color:var(--muted)}
  .step.on{border-bottom-color:var(--accent);color:var(--text);font-weight:600}
  .step small{display:block;font-size:11px;color:var(--faint);font-weight:400}
  .map-row{display:grid;grid-template-columns:1fr 30px 1fr 96px;gap:10px;align-items:center;
    padding:8px 0;border-bottom:1px solid #eef0f3;font-size:13px}
  .map-row .arrow{text-align:center;color:var(--faint)}

  /* toast */
  #toast{
    position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(14px);
    background:#161b25;color:#fff;padding:10px 16px;border-radius:8px;font-size:13px;
    box-shadow:var(--shadow-lg);opacity:0;transition:all .2s;z-index:80;pointer-events:none;
  }
  #toast.show{opacity:1;transform:translateX(-50%) translateY(0)}

  .banner{
    background:var(--warn-soft);border:1px solid #f3ddb6;color:#7a4a08;
    padding:9px 13px;border-radius:7px;font-size:12.5px;margin-bottom:14px;
  }


/* =====================================================================
   Beyond the mockup
   Things the prototype did in JavaScript that the server now renders.
   Kept apart so the section above stays a clean diff against mockup.html.
   ===================================================================== */

/* The drawer is server-rendered, so it exists in the DOM only while open. */
#drawer:empty { box-shadow: none; }
#drawer form { display: contents; }

/* htmx swaps the drawer's contents; this is what animates it in. */
#scrim.show { opacity: 1; }

/* The prototype's role switcher was a dropdown over fake data. Here the
   titles you hold are real, so they are shown, not chosen. */
.scope-chips { display: flex; gap: 4px; align-items: center; }

/* Validation summary links to the field it names. */
.errbar ul { margin: 5px 0 0; padding-inline-start: 18px; }
.errbar li { margin: 2px 0; }

/* A required field that the server rejected keeps its message under it; the
   mockup only ever had one message slot, and so does this. */
.field .err:empty { display: none; }

/* Tables of settlements and allocations inside the drawer sit tighter than a
   full page table. */
.drawer-body table td { padding: 7px 8px; font-size: 12.5px; }
.drawer-body table th { padding: 7px 8px; }

/* Read-only surfaces (UA's ready-to-use list) shouldn't imply a row click. */
table.static tbody tr:hover { background: transparent; cursor: default; }

/* Form builder rows */
.fieldbuilder { width: 100%; font-size: 13px; }
.fieldbuilder input, .fieldbuilder select {
  width: 100%; padding: 5px 7px; border: 1px solid var(--border-strong); border-radius: 6px;
}
.formcard { text-decoration: none; color: inherit; display: block; }
.formcard:hover { border-color: var(--border-strong); }


/* ============================ responsive ============================
 *
 * This block is last in the file, and it has to stay last.
 *
 * It used to sit near the top, above the component rules. Media queries add no
 * specificity, so every declaration in it was quietly overridden by the plain
 * `aside{}`, `.kpis{}` and `.grid2{}` rules further down — same specificity,
 * later in the source, so they won. The off-canvas sidebar therefore never came
 * out on a phone: the 224px rail stayed in the layout, the content was pushed
 * off the right edge of the screen, and roughly a third of every page was
 * unreachable. Two more copies of the same breakpoints had been added further
 * down over time, which is what half-working looked like.
 *
 * Nothing here is clever. It only needs to come after what it overrides.
 */

/* The column stops growing at 1500px. Centre it, or a wide monitor puts the
   whole dashboard against one edge with a third of the screen left over. */
.content{ margin-inline:auto }

/* Desktop down to laptop: four KPIs across is too tight, and the 1.55/1 split
   under it stops being two readable panels. */
@media (max-width:1180px){
  .kpis{ grid-template-columns:repeat(2,1fr) }
  .grid2{ grid-template-columns:1fr }
}

@media (max-width:1100px){ .grid3{ grid-template-columns:1fr } }

/* Tablet and below: the sidebar becomes a drawer behind the ☰ button. */
@media (max-width:1024px){
  aside{ position:fixed; inset-block:0; inset-inline-start:0; transform:translateX(-100%);
         transition:transform .2s; z-index:60 }
  body.nav-open aside{ transform:translateX(0) }
  html[dir="rtl"] aside{ transform:translateX(100%) }
  html[dir="rtl"] body.nav-open aside{ transform:translateX(0) }
  #navToggle{ display:inline-flex }
  .grid2,.grid2b,.grid3{ grid-template-columns:1fr }
  #drawer{ width:100% }
  .content{ padding:var(--s3) }
  /* `header.topbar` and not `.topbar`: the base rule is element-qualified, so a
     bare class here would lose to it. The same trap as the one above. */
  header.topbar{ padding:0 var(--s3); gap:10px }
}

/* The topbar runs out of room before the content does. Density and direction
   are preferences rather than navigation, and the crumb repeats the title. */
@media (max-width:860px){
  .topbar .density, .topbar .crumb{ display:none }
}

@media (max-width:640px){
  .kpis{ grid-template-columns:1fr }
  .role-wrap span{ display:none }
  .page-head{ flex-wrap:wrap }

  /* A panel head is a title, a subtitle and sometimes two buttons. On a phone
     that is several lines, not one clipped line. The month arrows carry an
     inline `margin-inline-start:auto` that only !important can undo. */
  .panel-head{ flex-wrap:wrap; row-gap:6px }
  .panel-head .btn{ margin-inline-start:0 !important }
  /* The subtitle is a sentence, not a tag. Beside the heading it had about
     90px and was cut mid-word; on its own line it simply wraps. */
  .panel-head .sub{ flex-basis:100%; }

  /* In a narrow table the bar beside a figure is the first thing to go: it
     repeats what the ordering already says, and it was pushing the amount --
     the column people came for -- off the side of the screen. */
  .mini-bar{ display:none }

  /* Eight months will not fit across 390px, and pretending otherwise collides
     the labels into each other. Give each column a floor and let the chart
     scroll sideways — the panel still shows where the peaks are. */
  .bars{ overflow-x:auto; min-width:0; padding-bottom:var(--s1) }
  .bar-col{ min-width:54px }

  /* Ranked rows become two lines: the name gets the full width, then the bar
     and its two figures sit under it. At 88px the names were all ellipsis. */
  .split-row{ flex-wrap:wrap; gap:4px 8px; margin-bottom:13px }
  .split-row .nm{ width:100%; color:var(--text) }
  .split-bar{ flex:1 1 auto }
  .split-row .vl, .split-row .pct{ width:auto }
}
