/* Biller Bro — Stylesheet */

    :root{
      --indigo:#03234e; --indigo-dark:#03234e; --indigo-light:#eef2ff;
      --green:#059669; --green-light:#ecfdf5;
      --red:#dc2626; --red-light:#fef2f2;
      --amber:#d97706; --amber-light:#fffbeb;
      --ink:#111827; --gray:#6b7280; --gray-light:#9ca3af;
      --border:#e5e7eb; --bg:#f9fafb; --card:#ffffff;
      --field:#fcfcfd; --focus-ring:rgba(79,70,229,.14);
      --shadow-sm:0 1px 2px rgba(16,24,40,.04);
      --shadow:0 1px 3px rgba(16,24,40,.06), 0 1px 2px rgba(16,24,40,.04);
      --shadow-lg:0 12px 32px rgba(16,24,40,.12), 0 2px 6px rgba(16,24,40,.06);
    }
    *{box-sizing:border-box; margin:0; padding:0;}
    body{
      font-family:"Poppins";
      background:var(--bg); color:var(--ink); font-size:14px;
    }
    a{color:inherit;}
    ::-webkit-scrollbar{width:8px; height:8px;}
    ::-webkit-scrollbar-thumb{background:#d1d5db; border-radius:4px;}

    /* ---------- Layout ---------- */
    /* THE APP IS A SHELL, NOT A LONG PAGE.
       The sidebar used to be `position:sticky` and the topbar likewise, which
       is only ever as reliable as the page's scroll box — on a phone both slid
       away with the dashboard under them, and a sidebar pinned at 100vh with
       seventeen nav items in it simply spilled its bottom half off the screen
       with nothing able to reach it.
       So nothing sticks any more. The viewport is the frame: #app is exactly
       one screen tall and never scrolls, the sidebar and the topbar are fixed
       furniture inside it, and the only thing that moves is .content. That
       holds identically on a desktop, a tablet and a phone, and it is why the
       header stays put.
       100dvh over 100vh: a phone's address bar eats into 100vh, so a 100vh
       shell is taller than what you can see and the bottom of the nav hides
       behind the browser chrome. dvh is the visible height; the plain 100vh
       above it is the fallback for anything that has not heard of dvh. */
    #app{display:flex; height:100vh; height:100dvh; overflow:hidden;}
    .sidebar{
      width:220px; background:#111827; color:#e5e7eb; flex-shrink:0;
      display:flex; flex-direction:column; padding:20px 0;
      height:100%; overflow:hidden;
    }
    .brand{padding:0 20px 20px; font-weight:700; font-size:18px; color:#fff; display:flex; align-items:center; gap:8px; border-bottom:1px solid #1f2937; margin-bottom:12px; flex-shrink:0;}
    .brand .dot{width:10px; height:10px; border-radius:50%; background:var(--indigo);}

    /* The scrolling middle of the sidebar. flex:1 takes whatever is left after
       the brand, the company chip and the foot have had theirs; min-height:0 is
       what actually lets it shrink — without it a flex item refuses to go below
       its content height and the overflow never engages. */
    .nav-scroll{
      flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain;
      scrollbar-width:thin; scrollbar-color:#374151 transparent;
    }
    .nav-scroll::-webkit-scrollbar{width:6px;}
    .nav-scroll::-webkit-scrollbar-thumb{background:#374151; border-radius:3px;}
    .nav-scroll::-webkit-scrollbar-track{background:transparent;}

    /* Closes the drawer. Hidden until the sidebar becomes one — see the
       820px block. */
    .drawer-close{
      display:none; margin-left:auto; background:none; border:none; color:#9ca3af;
      font-size:26px; line-height:1; cursor:pointer; padding:0 4px;
    }
    .drawer-close:hover{color:#fff;}
    .nav-item{
      display:flex; align-items:center; gap:10px; padding:11px 20px; cursor:pointer;
      color:#9ca3af; font-weight:500; transition:.15s; border-left:3px solid transparent;
    }
    .nav-item:hover{color:#fff; background:#1f2937;}
    .nav-item.active{
      color:#fff; background:#1f2937; border-left-color:var(--indigo); font-weight:600;
    }
    .nav-icon{width:18px; text-align:center;}
    /* A plain + reads much smaller than the symbol glyphs beside it at the
       same font-size, so it gets a size and weight bump to look the same
       visual weight as the rest of the sidebar's icons. */
    .nav-icon-plus{font-size:16px; font-weight:700; line-height:1;}
    .main{flex:1; min-width:0; display:flex; flex-direction:column; height:100%; overflow:hidden;}
    /* Not sticky — a fixed row of the shell. It cannot scroll away because
       there is no scroll under it to carry it off. */
    .topbar{
      background:var(--card); border-bottom:1px solid var(--border); padding:16px 28px;
      display:flex; align-items:center; justify-content:space-between;
      flex-shrink:0; z-index:10;
    }
    .topbar h1{font-size:19px; font-weight:700; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
    /* The scrolling region — for the screens that are a document. See .fit. */
    .content{
      padding:24px 28px; flex:1 1 auto; min-height:0;
      overflow-y:auto; overflow-x:hidden; -webkit-overflow-scrolling:touch;
    }

    /* =====================================================
       FITTED SCREENS — the list scrolls, the screen does not
       =====================================================

       A list screen is not a document. The toolbar that filters it, and the
       pager that says which hundred rows you are looking at, are controls: they
       belong on the screen at all times, not eight hundred rows above the
       thumb. So on these screens the page itself has no scroll at all. The
       header, the stat tiles, the toolbar and the pager are fixed furniture,
       and the only thing that moves is the rows inside .table-wrap.

       WHICH SCREENS. The markup says so, not a list in here that would drift
       out of step with it: a view carrying `data-fit` is one of these, and
       syncContentFit() in script.js puts .fit on .content when such a view is
       the one on show. The detail screens — an invoice, a costing sheet, the
       masters — are documents, six panels of prose and figures read top to
       bottom, and they keep the ordinary page scroll.

       WHERE IT APPLIES. Everywhere there is enough height to be worth it — a
       phone held upright included, which is where it matters most, because a
       phone is the screen a toolbar scrolls off fastest. The one guard is
       height: under 560px, which is a phone turned on its side or a window
       dragged short, a fitted table would be four rows under a stat grid, so
       the plain page scroll is the better screen and none of this applies.

       min-height:0 appears on every link in the chain. A flex item will not go
       below its content's height without it, so one missing link anywhere and
       the whole column grows past the viewport again. */
    @media(min-height:560px){
      .content.fit{
        overflow:hidden; display:flex; flex-direction:column;
        padding-bottom:20px;
      }
      .content.fit > .view.active{
        flex:1 1 auto; min-height:0; display:flex; flex-direction:column;
      }
      /* The tiles keep their own height; everything below shares what is left. */
      .content.fit > .view.active > .stat-grid,
      .content.fit > .view.active > .toolbar{flex:0 0 auto;}
      .content.fit > .view.active > .panel,
      .content.fit > .view.active > .dash-panes,
      .content.fit > .view.active > .two-col{flex:1 1 auto; min-height:0; margin-bottom:0;}
      .content.fit .dash-panes > .panel{min-height:0; flex:1 1 auto;}
      /* An info-panel is a paragraph explaining the screen, not a container for
         rows. It keeps its own height; the table below takes the rest. */
      .content.fit > .view.active > .panel.info-panel{flex:0 0 auto; margin-bottom:16px;}

      .content.fit .two-col > *{min-height:0;}
      .content.fit .panel{display:flex; flex-direction:column; min-height:0;}
      .content.fit .panel-head{flex:0 0 auto;}
      /* The rows. This is the one thing on the screen that scrolls. */
      .content.fit .table-wrap{flex:1 1 auto; min-height:0; max-height:none;}
      /* The pager sits under the rows rather than after them, so Next is in the
         same place on every page of every list. */
      .content.fit .panel > [id^="pager-"]{flex:0 0 auto;}
      .content.fit .pager{margin-bottom:-4px;}
      /* The rows scroll under their own heading, so the heading has to stay.
         The mobile block below switches this off for the screens that are not
         fitted, where the table is not a scroll box and a sticky row would
         stick to nothing. */
      .content.fit .table-wrap th{position:sticky; top:0; z-index:1;}
    }

    /* ---------- The fitted layout on a phone ----------
       Same shape, less of everything. A phone has about 760 usable pixels and
       the dashboard has to spend them on six tiles and two tables, so the tiles
       go two to a row at two thirds the size, the panels lose their padding,
       and what is left is split between the two tables — roughly seven rows
       each, both scrolling under headings that stay put.
       This is the screen the whole exercise was for: on a phone the toolbar and
       the pager are the first things to scroll away and the hardest to get
       back. */
    @media(max-width:820px) and (min-height:560px){
      .content.fit{padding:12px 12px 0;}
      .content.fit > .view.active > .stat-grid{
        grid-template-columns:repeat(2,1fr); gap:8px; margin-bottom:12px;
      }
      .content.fit .stat-card{padding:9px 11px; border-radius:10px;}
      .content.fit .stat-card .label{font-size:10px; letter-spacing:.02em;}
      .content.fit .stat-card .value{font-size:17px; margin-top:2px;}
      .content.fit .stat-card .sub{font-size:10.5px; margin-top:1px;}

      /* THE TOOLBAR IS FURNITURE NOW, SO ITS HEIGHT IS THE TABLE'S LOSS.
         Stacked one control per row, Invoices spent 200px of a 780px screen on
         a search box, two dropdowns and a button. The search box earns a row of
         its own; the two dropdowns share one. The max-width:none overrides the
         inline widths on those selects, which are there to stop them sprawling
         across a desktop toolbar. */
      .content.fit > .view.active > .toolbar{
        flex-direction:row; flex-wrap:wrap; align-items:stretch;
        margin-bottom:10px; gap:8px;
      }
      .content.fit > .view.active > .toolbar > .search-box{flex:1 1 100%; max-width:none;}
      .content.fit > .view.active > .toolbar > select{flex:1 1 calc(50% - 4px); max-width:none !important;}
      .content.fit > .view.active > .toolbar > .btn{flex:1 1 100%;}
      .content.fit .panel{padding:10px 11px; margin-bottom:0; border-radius:10px;}
      .content.fit .panel-head{margin-bottom:8px; padding-bottom:8px;}
      .content.fit .panel-head h3{font-size:14px;}

      /* Two panels stacked, each taking half of what is left and scrolling its
         own rows. `flex:1 1 0` rather than `1 1 auto` so they split evenly
         instead of by how many rows each happens to hold. */
      .content.fit > .view.active > .two-col{
        display:flex; flex-direction:column; gap:10px;
      }
      .content.fit > .view.active > .two-col > *{flex:1 1 0; min-height:0;}

      /* The bottom edge of the last panel wants clearing the home bar. */
      .content.fit > .view.active{padding-bottom:calc(12px + env(safe-area-inset-bottom));}

    }

    /* ---------- The dashboard's two tables ----------
       One at a time, in one full-width panel, at every width. See the markup
       for why it is no longer two panels side by side. */
    .dash-panes{display:flex; flex-direction:column; min-height:0;}
    .dash-panes > .panel{display:none; margin-bottom:0;}
    .dash-panes > .panel.pane-on{display:block;}
    /* Repeated under .content.fit, and not for tidiness: `.content.fit .panel`
       sets display:flex and is three classes, so it outranks the two-class rule
       above and would show BOTH tables on a fitted screen. These are four and
       five, so the hide sticks and the shown one still becomes the flex column
       its table needs to fill. */
    .content.fit .dash-panes > .panel{display:none;}
    .content.fit .dash-panes > .panel.pane-on{display:flex;}

    /* The two buttons that pick between them are plain .btn — nothing to style
       here. On a phone they share one row instead of taking one each, which the
       fitted toolbar rules would otherwise give them. */
    @media(max-width:820px){
      #dashSwitch .btn{flex:1 1 calc(50% - 5px); min-width:0;}
    }

    /* A LAPTOP IS NOT A DESKTOP.
       On a 1366x768 screen the six dashboard tiles at their full size wrap onto
       two rows and take 260px of a 640px working area, leaving the tables three
       visible rows each. The tiles are a glance, not the screen — so above a
       short window they tighten up and fit on one row, and the rows get the
       space back. */
    @media(min-width:821px) and (min-height:560px) and (max-height:900px){
      .content.fit > .view.active > .stat-grid{
        grid-template-columns:repeat(auto-fit,minmax(148px,1fr));
        gap:10px; margin-bottom:14px;
      }
      .content.fit .stat-card{padding:11px 13px;}
      .content.fit .stat-card .label{font-size:11px;}
      .content.fit .stat-card .value{font-size:19px; margin-top:3px;}
      .content.fit .stat-card .sub{font-size:11px; margin-top:2px;}
      .content.fit .panel{padding:14px 16px;}
      .content.fit .panel-head{margin-bottom:10px; padding-bottom:9px;}
    }

    /* ---------- Buttons ---------- */
    .btn{
      border:1px solid transparent; border-radius:9px; padding:9px 16px;
      font-size:13.5px; font-weight:600; font-family:inherit; line-height:1.3;
      cursor:pointer; display:inline-flex; align-items:center; justify-content:center; gap:7px;
      white-space:nowrap; transition:background .15s, border-color .15s, box-shadow .15s, transform .06s;
    }
    .btn:active{transform:translateY(1px);}
    .btn:focus-visible{outline:none; box-shadow:0 0 0 3px var(--focus-ring);}
    .btn-primary{background:var(--indigo); color:#fff; box-shadow:var(--shadow-sm);}
    .btn-primary:hover{background:var(--indigo-dark);}
    .btn-outline{background:#fff; color:var(--ink); border-color:var(--border); box-shadow:var(--shadow-sm);}
    .btn-outline:hover{background:#f9fafb; border-color:#d5d9e0;}
    .btn-danger{background:var(--red-light); color:var(--red); border-color:#fee2e2;}
    .btn-danger:hover{background:#fee2e2; border-color:#fecaca;}
    .btn-sm{padding:6px 11px; font-size:12px; border-radius:7px;}
    .btn-block{width:100%;}
    .btn:disabled{opacity:.5; cursor:not-allowed; transform:none;}

    /* ---------- Cards / stats ---------- */
    .stat-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:16px; margin-bottom:24px;}
    .stat-card{
      background:var(--card); border:1px solid var(--border); border-radius:12px;
      padding:18px 20px; box-shadow:var(--shadow-sm); transition:box-shadow .15s;
    }
    .stat-card:hover{box-shadow:var(--shadow);}
    .stat-card .label{color:var(--gray); font-size:12.5px; font-weight:600; text-transform:uppercase; letter-spacing:.03em;}
    .stat-card .value{font-size:26px; font-weight:800; margin-top:6px;}
    .stat-card .sub{font-size:12px; color:var(--gray-light); margin-top:4px;}
    .stat-card.profit .value{color:var(--green);}
    .stat-card.alert .value{color:var(--red);}

    .panel{
      background:var(--card); border:1px solid var(--border); border-radius:12px;
      padding:20px; margin-bottom:20px; box-shadow:var(--shadow-sm);
    }
    .panel-head{
      display:flex; align-items:center; justify-content:space-between; gap:12px;
      margin-bottom:14px; padding-bottom:12px; border-bottom:1px solid var(--border);
    }
    .panel-head h3{font-size:15px; font-weight:700;}
    .two-col{display:grid; grid-template-columns:1.4fr 1fr; gap:20px;}
    @media(max-width:980px){.two-col{grid-template-columns:1fr;}}

    /* WHY THE DASHBOARD RAN OFF THE RIGHT OF A PHONE.
       A grid or flex item is `min-width:auto` by default, which means it refuses
       to be narrower than its own content. Every table cell in here is
       white-space:nowrap, so a panel holding a five-column table had a
       min-content width of about 600px and simply grew to it — a 390px screen
       got a 607px panel, the .table-wrap inside never had anything to scroll
       because the panel had already made room, and the right-hand edge of every
       card sat off the screen.
       min-width:0 lets them shrink back to the column they were given; the
       overflow then lands where it belongs, on .table-wrap, which scrolls. */
    .two-col > *{min-width:0;}
    .panel{min-width:0;}
    .table-wrap{max-width:100%;}

    /* ---------- Tables ---------- */
    table{width:100%; border-collapse:collapse; font-size:13.5px;}
    th{
      text-align:left; padding:10px 12px; color:var(--gray); font-weight:700; font-size:11px;
      text-transform:uppercase; letter-spacing:.045em; white-space:nowrap;
      background:#fafbfc; border-bottom:1px solid var(--border);
      position:sticky; top:0; z-index:1;
    }
    thead th:first-child{border-top-left-radius:8px;}
    thead th:last-child{border-top-right-radius:8px;}
    td{padding:11px 12px; border-bottom:1px solid #f1f3f5; white-space:nowrap;}
    tbody tr:last-child td{border-bottom:none;}
    tbody tr{transition:background .12s;}
    tbody tr:hover td{background:#f8f9fc;}
    .table-wrap{overflow-x:auto; overflow-y:auto; max-height:70vh; border-radius:8px;}
    .badge{display:inline-block; padding:3px 10px; border-radius:99px; font-size:11px; font-weight:700; letter-spacing:.01em; white-space:nowrap;}
    .badge-green{background:var(--green-light); color:var(--green);}
    .badge-red{background:var(--red-light); color:var(--red);}
    .badge-amber{background:var(--amber-light); color:var(--amber);}
    .badge-gray{background:#f3f4f6; color:var(--gray);}
    .badge-indigo{background:var(--indigo-light); color:var(--indigo);}
    .row-actions{display:flex; gap:6px;}
    .empty-state{text-align:center; padding:40px 20px; color:var(--gray-light);}

    /* ---------- Toolbar / search ---------- */
    .toolbar{display:flex; gap:10px; align-items:center; margin-bottom:16px; flex-wrap:wrap;}

    /* ---------- Form controls ---------- */
    /* Every field in the portal is one of these, so they carry most of the
       feel of the thing. A field should look like something you can type in
       before you click it, say clearly that it has focus, and look plainly
       switched off when it is. */
    input[type=text], input[type=number], input[type=date], input[type=email],
    input[type=password], select, textarea{
      border:1px solid var(--border); border-radius:9px; padding:10px 13px;
      font-size:13.5px; font-family:inherit; line-height:1.4;
      width:100%; background:var(--field); color:var(--ink);
      transition:border-color .15s, box-shadow .15s, background .15s;
      -webkit-appearance:none; appearance:none;
    }
    textarea{resize:vertical; min-height:70px;}

    input::placeholder, textarea::placeholder{color:var(--gray-light);}

    input[type=text]:hover, input[type=number]:hover, input[type=date]:hover,
    input[type=email]:hover, input[type=password]:hover, select:hover, textarea:hover{
      border-color:#cbd0d8; background:#fff;
    }

    input:focus, select:focus, textarea:focus{
      outline:none; border-color:var(--indigo); background:#fff;
      box-shadow:0 0 0 3px var(--focus-ring);
    }

    /* Switched off, not broken: a read-only price is a fact, so it reads like
       one — flat, greyed, and with a cursor that says "not yours to change". */
    /* A value the form worked out rather than one that was typed. Still fully
       editable — typing in it simply makes it yours. */
    input.derived{color:var(--gray); font-style:italic;}
    input:disabled, select:disabled, textarea:disabled,
    input[readonly], textarea[readonly]{
      background:#f3f4f6; color:var(--gray); border-color:var(--border);
      cursor:not-allowed; box-shadow:none;
    }
    input:disabled:hover, select:disabled:hover{border-color:var(--border); background:#f3f4f6;}

    /* The browser's own arrow is inconsistent across platforms; this one is not. */
    select{
      padding-right:34px; cursor:pointer;
      background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%236b7280' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
      background-repeat:no-repeat; background-position:right 12px center;
    }
    select:disabled{background-image:none;}

    /* Number fields hold quantities and money, so they read right-aligned in
       tables but stay natural in forms. The spinners add nothing and take width. */
    input[type=number]{-moz-appearance:textfield;}
    input[type=number]::-webkit-outer-spin-button,
    input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none; margin:0;}

    input[type=date]::-webkit-calendar-picker-indicator{cursor:pointer; opacity:.55;}
    input[type=date]:hover::-webkit-calendar-picker-indicator{opacity:1;}

    input[type=checkbox]{
      width:16px; height:16px; accent-color:var(--indigo); cursor:pointer; flex:none;
    }

    .search-box{position:relative; max-width:300px; flex:1;}
    /* A magnifying glass drawn in the border, so the box says what it is for. */
    .search-box input{
      padding-left:34px;
      background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Cg fill='none' stroke='%239ca3af' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='6' cy='6' r='4.2'/%3E%3Cpath d='M9.2 9.2 12.5 12.5'/%3E%3C/g%3E%3C/svg%3E");
      background-repeat:no-repeat; background-position:left 12px center;
    }

    .form-grid{display:grid; grid-template-columns:1fr 1fr; gap:14px 16px;}
    @media(max-width:720px){
      .form-grid, .form-grid-3{grid-template-columns:1fr;}
    }
    .form-field{display:flex; flex-direction:column; gap:6px; margin-bottom:14px;}
    .form-field label{
      font-size:12px; font-weight:700; color:var(--gray);
      letter-spacing:.01em;
    }
    .form-field.full{grid-column:1/-1;}

    /* A phone field is a country/dial code beside the number itself — the
       select stays a fixed width so the number field gets the room. */
    .phone-input-row{display:flex; gap:6px;}
    .phone-input-row input{flex:1 1 auto; min-width:0;}
    .phone-code-select{flex:0 0 92px; width:92px; padding-left:6px; padding-right:2px;}


    /* ---------- Modal ---------- */
    .overlay{
      display:none; position:fixed; inset:0; background:rgba(17,24,39,.45);
      backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
      align-items:center; justify-content:center; z-index:100; padding:20px;
    }
    .overlay.open{display:flex; animation:fadein .15s ease;}
    .modal{
      background:#fff; border-radius:16px; width:100%; max-width:480px;
      max-height:88vh; overflow-y:auto; padding:26px 28px;
      box-shadow:var(--shadow-lg); animation:modalin .18s cubic-bezier(.2,.8,.3,1);
    }
    .modal h2{font-size:17px; margin-bottom:18px;}
    /* The buttons sit on a rule so a long form has an obvious bottom edge. */
    .modal-actions{
      display:flex; justify-content:flex-end; gap:10px;
      margin-top:20px; padding-top:18px; border-top:1px solid var(--border);
    }
    @keyframes fadein{from{opacity:0;} to{opacity:1;}}
    @keyframes modalin{from{opacity:0; transform:translateY(10px) scale(.99);} to{opacity:1; transform:none;}}

    /* ---------- Toast ---------- */
    #toast{
      position:fixed; bottom:24px; right:24px; z-index:200; display:flex; flex-direction:column; gap:8px;
    }
    .toast-item{
      background:#111827; color:#fff; padding:12px 18px; border-radius:8px; font-size:13.5px;
      font-weight:500; box-shadow:0 8px 20px rgba(0,0,0,.2); min-width:220px; animation:slidein .2s ease;
    }
    .toast-item.err{background:var(--red);}
    .toast-item.ok{background:var(--green);}
    @keyframes slidein{from{transform:translateY(10px); opacity:0;} to{transform:translateY(0); opacity:1;}}

    /* ---------- Loader ---------- */
    /* Shown only once a request outlasts LOADER_DELAY_MS, then faded in over a
       further beat, so the eye never catches a spinner blinking on and off. */
    #loader{
      position:fixed; inset:0; background:rgba(255,255,255,.55); z-index:300;
      display:flex; align-items:center; justify-content:center;
      opacity:0; visibility:hidden; transition:opacity .12s ease-out, visibility 0s linear .12s;
    }
    #loader.open{opacity:1; visibility:visible; transition:opacity .12s ease-out, visibility 0s;}
    .spinner{width:34px; height:34px; border:3px solid var(--indigo-light); border-top-color:var(--indigo); border-radius:50%; animation:spin .7s linear infinite;}
    @keyframes spin{to{transform:rotate(360deg);}}
    @media(prefers-reduced-motion:reduce){
      #loader{transition:none;}
      .spinner{animation-duration:1.4s;}
    }

    .muted{color:var(--gray);}
    .view{display:none;}
    .view.active{display:block;}
    .flex-between{display:flex; align-items:center; justify-content:space-between;}
    .profit-pos{color:var(--green); font-weight:700;}
    .profit-neg{color:var(--red); font-weight:700;}

    /* ---------- Mobile nav ---------- */
    .hamburger{
      display:none; background:none; border:none; font-size:22px; cursor:pointer;
      color:var(--ink); padding:6px 10px; border-radius:8px; line-height:1;
      /* 44px is the smallest target a thumb hits reliably. */
      min-width:44px; min-height:44px; align-items:center; justify-content:center;
    }
    .hamburger:active{background:#f3f4f6;}
    .sidebar-backdrop{display:none; position:fixed; inset:0; background:rgba(17,24,39,.45); z-index:39;}
    .sidebar-backdrop.open{display:block;}

    /* ---------- Tablet ---------- */
    /* Between a phone and a laptop the sidebar still earns its place, but 220px
       of it against a 900px screen leaves the tables nothing. Narrower rail,
       tighter gutters, same layout. */
    @media(min-width:821px) and (max-width:1100px){
      .sidebar{width:188px;}
      .nav-item{padding:10px 14px; font-size:13px;}
      .nav-sep{padding-left:14px;}
      .topbar{padding:14px 18px;}
      .content{padding:18px;}
      .stat-grid{grid-template-columns:repeat(auto-fit,minmax(170px,1fr)); gap:12px;}
    }

    /* ---------- Phone / tablet in portrait ---------- */
    @media(max-width:820px){
      .hamburger{display:inline-flex;}
      .drawer-close{display:block;}
      /* A drawer over the shell. height:100% is the shell's own height, which
         is already the visible viewport, so the nav's bottom is never behind
         the browser's address bar. */
      .sidebar{
        position:fixed; left:0; top:0; z-index:40;
        height:100%; height:100dvh; width:min(80vw,280px);
        transform:translateX(-100%); transition:transform .2s ease; box-shadow:0 0 30px rgba(0,0,0,.25);
        padding-top:max(20px, env(safe-area-inset-top));
      }
      .sidebar.open{transform:translateX(0);}
      @media(prefers-reduced-motion:reduce){ .sidebar{transition:none;} }

      .topbar{padding:10px 12px; gap:8px;}
      .topbar h1{font-size:16px;}
      .topbar .btn{padding:8px 12px; font-size:12.5px;}
      .content{padding:14px 12px calc(20px + env(safe-area-inset-bottom));}

      .stat-grid{grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:10px; margin-bottom:16px;}
      .stat-card{padding:13px 14px;}
      .stat-card .value{font-size:20px;}
      .panel{padding:13px; border-radius:10px;}
      .panel-head{flex-wrap:wrap;}
      .toolbar{flex-direction:column; align-items:stretch;}
      .search-box{max-width:none;}
      .form-grid{grid-template-columns:1fr;}

      /* ONE VERTICAL SCROLL, NOT TWO.
         The 70vh cap plus sticky headers is right on a desktop. On a phone it
         puts a second scroll box inside the one the thumb is already using, and
         the two fight over every swipe. Here the table grows to its full height
         and only its columns scroll sideways. */
      .table-wrap{max-height:none; border-radius:6px;}
      th{position:static;}
      th, td{padding:8px 10px; font-size:12.5px;}

      /* A sheet, not a floating card: full width, and capped against the
         visible viewport so the Save row is never under the address bar. */
      .overlay{padding:10px; align-items:flex-end;}
      .modal{
        max-width:100%; border-radius:14px; padding:16px;
        max-height:calc(100vh - 20px); max-height:calc(100dvh - 20px);
      }
      /* Save and Cancel ride along the bottom of a long form instead of sitting
         at the end of it, so a twenty-field customer form does not have to be
         scrolled to the bottom to be saved. The negative side margins take the
         bar out to the modal's edges. */
      .modal-actions{
        position:sticky; bottom:-16px; z-index:2; background:#fff;
        margin:18px -16px -16px; padding:12px 16px calc(12px + env(safe-area-inset-bottom));
        border-top:1px solid var(--border);
      }
      .modal-actions .btn{flex:1;}

      #toast{left:12px; right:12px; bottom:calc(12px + env(safe-area-inset-bottom));}
      .toast-item{min-width:0;}
      .pager{justify-content:center;}
    }

    /* iOS zooms the whole page in when a field smaller than 16px takes focus,
       and never zooms back out. Touch devices only, so the desktop keeps its
       13.5px fields. */
    @media(hover:none) and (pointer:coarse){
      input[type=text], input[type=number], input[type=date], input[type=email],
      input[type=password], select, textarea{font-size:16px; padding:11px 13px;}
      .btn{min-height:40px;}
      .nav-item{padding-top:13px; padding-bottom:13px;}
    }

    /* =====================================================
       MULTI-COMPANY ADDITIONS
       ===================================================== */

    .hidden{display:none !important;}

    /* ---------- Auth screens ---------- */
    .auth-wrap{
      min-height:100vh; display:flex; align-items:center; justify-content:center;
      padding:32px 16px; background:linear-gradient(160deg,#eef2ff 0%,#f9fafb 45%,#f9fafb 100%);
    }
    .auth-wrap.hidden{display:none !important;}
    .auth-card{
      background:var(--card); border:1px solid var(--border); border-radius:16px;
      width:100%; max-width:520px; padding:30px 32px;
      box-shadow:0 12px 40px rgba(17,24,39,.08);
    }
    .auth-brand{
      display:flex; align-items:center; gap:8px; font-weight:700; font-size:17px;
      padding-bottom:18px; margin-bottom:22px; border-bottom:1px solid var(--border);
    }
    .auth-brand .dot{width:10px; height:10px; border-radius:50%; background:var(--indigo);}
    .auth-pane{display:none;}
    .auth-pane.active{display:block;}
    .auth-pane h1{font-size:20px; font-weight:800; margin-bottom:6px;}
    .auth-sub{color:var(--gray); font-size:13px; margin-bottom:20px;}
    .btn-block{width:100%; justify-content:center; padding:11px 16px; margin-top:6px;}
    .auth-foot{margin-top:16px; text-align:center; font-size:13px; color:var(--gray);}
    .auth-foot a{color:var(--indigo); font-weight:600; text-decoration:none;}
    .auth-foot a:hover{text-decoration:underline;}
    .section-label{
      font-size:11.5px; font-weight:700; text-transform:uppercase; letter-spacing:.05em;
      color:var(--indigo); margin:22px 0 12px; padding-top:16px; border-top:1px solid var(--border);
    }

    /* ---------- Sidebar company + user ---------- */
    .company-chip{
      margin:0 12px 14px; padding:10px 12px; background:#1f2937; border-radius:10px;
      border-left:3px solid var(--indigo);
    }
    .company-name{color:#fff; font-weight:700; font-size:13.5px; line-height:1.3;
      overflow:hidden; text-overflow:ellipsis;}
    .company-meta{color:#9ca3af; font-size:11.5px; margin-top:2px;}
    .nav-sep{
      padding:16px 20px 6px; font-size:10.5px; font-weight:700; letter-spacing:.06em;
      text-transform:uppercase; color:#6b7280;
    }
    .company-chip{flex-shrink:0;}
    /* The foot no longer needs margin-top:auto to be pushed down — .nav-scroll
       takes the slack above it — but it must not be squeezed by a long nav. */
    .sidebar-foot{
      flex-shrink:0; margin-top:12px; padding:16px 14px 0; border-top:1px solid #1f2937;
      padding-bottom:max(0px, env(safe-area-inset-bottom));
    }
    .user-chip{display:flex; align-items:center; gap:10px; margin-bottom:10px;}
    .avatar{
      width:32px; height:32px; border-radius:50%; background:var(--indigo); color:#fff;
      display:flex; align-items:center; justify-content:center; font-weight:700; flex-shrink:0;
    }
    .user-meta{min-width:0;}
    .user-name{color:#fff; font-size:13px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
    .user-role{color:#9ca3af; font-size:11.5px; text-transform:uppercase; letter-spacing:.04em;}
    /* THREE BUTTONS DOWN HERE NOW, NOT TWO.
       Password, Signature and Sign out do not fit across the sidebar in a row, so
       they wrap instead of the third one being cut off the edge. `flex:1` with a
       basis wide enough to read means two sit side by side and the third drops to
       its own line, rather than three squeezing into illegible slivers. */
    .foot-actions{display:flex; gap:6px; flex-wrap:wrap;}
    .foot-actions .btn{flex:1 1 calc(50% - 3px); justify-content:center; white-space:nowrap;}

    /* ---------- Misc components ---------- */
    .hint{
      font-size:12.5px; color:#4b5563; background:var(--indigo-light);
      border-left:3px solid var(--indigo); border-radius:0 9px 9px 0;
      padding:11px 14px; margin-bottom:14px; line-height:1.55;
    }
    .hint:empty{display:none;}

    .split-table{width:100%; border-collapse:collapse; margin-top:8px; font-size:12px;}
    .split-table td{padding:3px 0;}
    .split-table td:last-child{text-align:right; font-weight:700; white-space:nowrap;}

    /* ---------- Line editors: products on a batch, drops on a trip ---------- */
    /* A consignment or a trip is a header plus repeating lines, so both forms
       are a small editable table rather than a fixed set of fields. */
    .section-head{
      font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.04em;
      color:var(--indigo); margin:18px 0 10px;
    }
    .line-table-wrap{overflow-x:auto; margin-bottom:10px;}
    /* Eight columns since the line editor gained a list price, a discount and the
       rate derived from them, plus a case/piece unit picker in the quantity
       column, so the minimum is wider than it was. The wrapper scrolls
       horizontally on a narrow screen rather than squeezing the inputs down to
       something nobody can type a number into. */
    .line-table{width:100%; border-collapse:collapse; min-width:1080px;}
    .line-table th{
      text-align:left; font-size:10.5px; font-weight:700; color:var(--gray);
      text-transform:uppercase; letter-spacing:.03em; padding:0 6px 6px; white-space:nowrap;
    }
    .line-table td{padding:3px 6px 3px 0; vertical-align:middle;}
    .line-table td:first-child{padding-left:0;}
    .line-table input, .line-table select{width:100%; padding:7px 9px; font-size:13px;}
    .line-table .line-value{font-weight:700; white-space:nowrap; font-size:13px;}
    /* The discount cell holds a number and, beside it, whether that number is a
       flat amount or a percentage of list price — narrower than the other
       columns share, so the two sit on one line instead of stacking. */
    .line-table .discount-cell{display:flex; gap:4px; min-width:130px;}
    .line-table .discount-cell input{flex:1 1 auto; min-width:0;}
    .line-table .discount-type{flex:0 0 56px; width:56px; padding:7px 4px; font-size:12px;}
    /* Quantity plus which unit it is counted in — a case (the product's own
       Unit) or a single piece sold out of one. Only products with more than
       one piece per case get the dropdown; everything else just names its
       unit, since "case" and "piece" would be the same thing. */
    .line-table .qty-unit-row{display:flex; gap:4px; min-width:118px;}
    .line-table .qty-unit-row input{flex:1 1 auto; min-width:0;}
    .line-table .unit-mode-select{flex:0 0 64px; width:64px; padding:7px 4px; font-size:12px;}
    .line-table .unit-fixed-label{flex:0 0 auto; font-size:11px; white-space:nowrap; align-self:center;}
    .line-table .unit-price-hint{font-size:10px; font-weight:400; white-space:nowrap;}
    .line-table .line-drop{
      background:none; border:none; color:var(--red); cursor:pointer;
      font-size:17px; line-height:1; padding:4px 6px;
    }
    .line-table .line-drop:hover{color:#991b1b;}

    /* One stop of a trip: the point it dropped at, and what came off there. */
    .stop-card{
      border:1px solid var(--border); border-radius:10px; padding:14px 16px; margin-bottom:12px;
      background:#fcfcfd;
    }
    .stop-head{display:flex; align-items:center; gap:10px; margin-bottom:10px;}
    .stop-num{
      flex:none; width:26px; height:26px; border-radius:50%; background:var(--indigo);
      color:#fff; font-size:12px; font-weight:700; display:flex; align-items:center;
      justify-content:center;
    }
    .stop-head .form-field{flex:1; margin-bottom:0;}
    .stop-head .btn{flex:none;}

    /* ---------- The three documents, drawn as a road ---------- */
    /* Quotation → invoice → delivery order. Showing where an order has got to,
       and the one button that moves it on, is the whole navigation. */
    .stage-bar{display:flex; gap:10px; flex-wrap:wrap;}
    .stage{
      flex:1; min-width:190px; display:flex; align-items:center; gap:12px;
      border:1px solid var(--border); border-radius:10px; padding:12px 14px;
    }
    .stage-num{
      flex:none; width:28px; height:28px; border-radius:50%; display:flex;
      align-items:center; justify-content:center; font-size:13px; font-weight:700;
      background:#f3f4f6; color:var(--gray);
    }
    .stage.current{border-color:var(--indigo); background:var(--indigo-light);}
    .stage.current .stage-num{background:var(--indigo); color:#fff;}
    .stage.done .stage-num{background:var(--green); color:#fff;}
    .stage.todo{opacity:.6;}
    .stage-body{min-width:0;}
    .stage-label{font-size:11px; font-weight:700; text-transform:uppercase;
      letter-spacing:.04em; color:var(--gray);}
    .stage-no{font-size:14px; font-weight:700;}
    .stage-date{font-size:11.5px; color:var(--gray);}
    .stage-action{
      display:flex; align-items:center; gap:12px; flex-wrap:wrap;
      margin-top:14px; padding-top:14px; border-top:1px solid var(--border);
    }
    .stage-action label{
      font-size:11px; font-weight:700; text-transform:uppercase;
      letter-spacing:.04em; color:var(--gray); margin:0;
    }
    .stage-action select{width:auto; min-width:150px;}
    .stage-action .muted{font-size:12.5px;}
    /* The quotation screen's action bar is a panel on its own, with no stage road
       above it, so the rule that separates the two has nothing to separate. */
    .panel > .stage-action:first-child{margin-top:0; padding-top:0; border-top:none;}

    /* A VOIDED INVOICE, IN THE LIST.
       Struck through rather than hidden or dropped: the number still exists, the
       customer may be holding the copy that was handed to them, and the series
       has to read without a gap in it. Greyed as well as struck, because a
       strike-through alone is easy to miss at a glance down a long table. */
    tr.row-void td{color:var(--gray); text-decoration:line-through;}
    tr.row-void td .badge, tr.row-void td .row-actions,
    tr.row-void td.row-actions{text-decoration:none;}

    /* A batch row that opens to show its product lines. */
    .row-toggle{
      background:none; border:none; cursor:pointer; color:var(--indigo);
      font-weight:700; font-size:13px; padding:0; text-align:left;
    }
    tr.line-row td{background:var(--indigo-light); font-size:12.5px;}
    tr.line-row td:first-child{padding-left:26px;}
    .unit-tag{
      display:inline-block; background:#f3f4f6; color:var(--gray); border-radius:5px;
      padding:1px 6px; font-size:11px; font-weight:700;
    }
    /* The currency symbol stamped into money column headings and field labels.
       Filled in from the company's own currency by applyCurrencyLabels(), and
       styled as a quiet unit so it reads alongside the label, not as part of it.
       :empty keeps the gap from showing before the session has loaded. */
    .cur{color:var(--gray); font-weight:600;}
    .cur:not(:empty)::before{content:"(";}
    .cur:not(:empty)::after{content:")";}
    .panel-body{padding-top:4px;}
    .check{display:flex; gap:10px; align-items:flex-start; margin-bottom:12px; font-size:13.5px; cursor:pointer;}
    .check input{width:16px; height:16px; margin-top:2px; flex-shrink:0; accent-color:var(--indigo);}
    .check-row{display:flex; gap:20px; flex-wrap:wrap; margin-top:6px;}
    .check-row .check{margin-bottom:0;}
    .info-panel table.plain td{border:none; padding:6px 12px 6px 0; white-space:normal;}
    .info-panel table.plain tr:hover td{background:none;}
    .info-panel h3{font-size:14px; font-weight:700; margin-bottom:10px;}

    @media(max-width:820px){
      .auth-card{padding:22px 18px;}
      .auth-wrap{padding:16px 12px;}
    }

    /* =====================================================
       OWNER CONSOLE + READ-ONLY PROFILE
       ===================================================== */

    .owner-dot{background:#d97706 !important;}
    .owner-sidebar{background:#1c1917;}
    .owner-sidebar .nav-item.active{border-left-color:#d97706;}
    .owner-chip{border-left-color:#d97706 !important; background:#292524 !important;}

    /* Read-only company profile shown to company admins */
    .profile-grid{
      display:grid; grid-template-columns:minmax(160px,auto) 1fr; gap:0 20px;
      margin-top:4px;
    }
    .profile-grid dt{
      font-size:12.5px; font-weight:600; color:var(--gray);
      padding:9px 0; border-bottom:1px solid #f3f4f6;
    }
    .profile-grid dd{
      font-size:13.5px; padding:9px 0; border-bottom:1px solid #f3f4f6; word-break:break-word;
    }
    .profile-grid dt:last-of-type, .profile-grid dd:last-of-type{border-bottom:none;}
    @media(max-width:640px){
      .profile-grid{grid-template-columns:1fr; gap:0;}
      .profile-grid dt{padding-bottom:0; border-bottom:none;}
      .profile-grid dd{padding-top:2px;}
    }

    /* THE LETTERHEAD SETTING — the logo beside the controls that change it.
       The preview box is a fixed frame with a checked ground behind it, so a
       logo saved on a transparent background reads as transparent here instead
       of looking like a white rectangle on a white panel. */
    .logo-setting{display:flex; gap:18px; align-items:flex-start; flex-wrap:wrap; margin-top:12px;}
    .logo-preview{
      flex:0 0 auto; width:220px; height:96px; border:1px solid var(--border);
      border-radius:8px; display:flex; align-items:center; justify-content:center;
      padding:8px; background-color:#fff;
      background-image:
        linear-gradient(45deg,#f3f4f6 25%,transparent 25%,transparent 75%,#f3f4f6 75%),
        linear-gradient(45deg,#f3f4f6 25%,transparent 25%,transparent 75%,#f3f4f6 75%);
      background-size:14px 14px; background-position:0 0, 7px 7px;
    }
    .logo-preview img{max-width:100%; max-height:100%; object-fit:contain;}
    .logo-controls{display:flex; flex-direction:column; gap:8px; align-items:flex-start;}
    .form-field-wide{grid-column:1 / -1;}

    /* A bill is read for its text, so its preview box is tall rather than the
       logo's wide letterhead shape — a phone photo of a receipt is portrait. */
    .proof-preview{width:110px; height:150px;}

    /* A plain full-size look at a stored photo (so far, just a bill/receipt). */
    .image-preview-modal{max-width:min(90vw,640px);}
    .image-preview-body{
      display:flex; align-items:center; justify-content:center;
      background:#f3f4f6; border-radius:8px; padding:10px; max-height:75vh; overflow:auto;
    }
    .image-preview-body img{max-width:100%; max-height:70vh; object-fit:contain;}

    /* One terms box per document. Monospaced line height rather than the tight
       form spacing, because what is being read here is a list of sentences and
       the line breaks between them are the data. */
    .terms-doc{margin-top:16px;}
    .terms-doc:first-child{margin-top:8px;}
    .terms-doc label{display:block; font-size:13px; margin-bottom:2px;}
    .terms-doc textarea{width:100%; margin-top:6px; line-height:1.6;}
    .terms-doc .field-hint{display:block;}
    @media(max-width:640px){
      .logo-preview{width:100%; }
    }

    /* Owner tables carry more text per cell than the app tables do */
    .wrap-cell{white-space:normal; min-width:170px; line-height:1.45;}
    hr.mini{border:none; border-top:1px solid var(--border); margin:6px 0;}
    .field-hint{font-size:11.5px; color:var(--gray-light); margin-top:2px;}
    code{
      background:#f3f4f6; padding:1px 5px; border-radius:4px;
      font-size:12.5px; font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
    }
    #view-create .panel-body{max-width:900px;}

    /* =====================================================
       ORDERS
       ===================================================== */

    .order-actions{display:flex; gap:8px; align-items:center; flex-wrap:wrap;}
    .order-actions select{
      width:auto; min-width:130px; padding:7px 10px; font-size:12.5px;
    }
    td a{color:var(--indigo); font-weight:600; text-decoration:none;}
    td a:hover{text-decoration:underline;}
    .sheet-link{
      display:inline-flex; align-items:center; gap:4px; font-size:11.5px;
      color:var(--indigo); font-weight:600; text-decoration:none; margin-top:3px;
    }
    .sheet-link:hover{text-decoration:underline;}

    @media(max-width:820px){
      .order-actions{width:100%; margin-top:10px;}
      .order-actions select, .order-actions .btn{flex:1;}
    }

    /* =====================================================
       PRODUCT / COSTING FORMS
       ===================================================== */

    /* THE LINE EDITORS OUTGREW 720px.
       A quotation or invoice line is now eight columns — product, quantity, list
       price, less, rate, line total, notes, remove — and at 720 the last three
       were pushed off the edge behind a scrollbar nobody noticed, so the notes
       field and the remove button were effectively invisible. 1120 fits the lot
       on a laptop; narrower screens fall back to the full width below, and the
       wrapper still scrolls on a phone. */
    .modal-wide{max-width:1120px;}
    .modal-title{text-align:center; font-size:18px; margin-bottom:20px;}
    .section-title{
      text-align:center; font-size:12px; font-weight:800; letter-spacing:.09em;
      text-transform:uppercase; color:var(--indigo); margin:22px 0 14px;
      position:relative;
    }
    .section-title::before, .section-title::after{
      content:''; position:absolute; top:50%; width:calc(50% - 100px); height:1px; background:var(--border);
    }
    .section-title::before{left:0;}
    .section-title::after{right:0;}
    .form-grid-3{grid-template-columns:1fr 1fr 1fr;}
    table.plain td.num{text-align:right; white-space:nowrap;}
    table.plain tr.rc-total td{border-top:1px solid var(--border); font-weight:700;}
    #costLayerTable tr.rc-total td{border-top:2px solid var(--indigo); color:var(--indigo);}

    @media(max-width:1180px){
      .modal-wide{max-width:100%;}
    }
    @media(max-width:820px){
      .form-grid-3{grid-template-columns:1fr;}
      .section-title::before, .section-title::after{display:none;}
    }


    /* ---------- Pagination ---------- */
    /* The controls under a long table. renderPager only draws them when a list
       runs past one page, so a short list looks exactly as it did before. */
    .pager{
      display:flex; align-items:center; justify-content:space-between;
      gap:12px; flex-wrap:wrap; padding:10px 14px;
      border-top:1px solid var(--border); font-size:13px;
    }
    .pager-info{color:var(--gray);}
    .pager-info b{color:var(--ink);}
    .pager-buttons{display:flex; align-items:center; gap:8px;}
    .pager-page{color:var(--gray); white-space:nowrap;}
    .pager button[disabled]{opacity:.45; cursor:not-allowed;}


    /* ---------- Whose rows am I looking at? ---------- */
    /* The scope switch on the Invoices, Quotations and Collections toolbars.
       Hidden outright for an administrator — see applyScopeControls — because
       their list is the company's and a switch with one honest setting is just
       a thing to wonder about. */
    .scope-select{font-weight:600;}
    .scope-note{
      display:inline-flex; align-items:center; gap:6px;
      font-size:12px; color:var(--gray); white-space:nowrap;
    }

    /* A date box sitting in a toolbar with its own word in front of it. */
    .toolbar-label{
      display:inline-flex; align-items:center; gap:7px;
      font-size:13px; color:var(--gray); white-space:nowrap;
    }
    .toolbar-label input{
      padding:8px 10px; border:1px solid var(--border); border-radius:8px;
      font-family:inherit; font-size:13px; color:var(--ink); background:#fff;
    }

    /* The small print under a column heading that carries a caveat — the
       Outstanding column is counted over a different period from the ones
       beside it, and the heading is the only place that can say so. */
    .th-note{
      display:block; font-weight:500; text-transform:none; letter-spacing:0;
      font-size:10px; color:var(--gray); margin-top:1px;
    }

    /* The totals line under the performance table. */
    #performanceTable tfoot td{
      font-weight:700; background:var(--bg); border-top:2px solid var(--border);
    }
    /* The row currently drilled into, so the detail panel below has something
       pointing at it. */
    tr.row-picked td{background:rgba(79,70,229,.07);}
