  :root{
    /* Project accent hue. Set per project on <html> or in a :root block;
       155 is the reference green. --ok/--warn/--bad and --s1..--s6 stay
       fixed: they are semantic, not the project accent. */
    --hue:155;
    --bg:#f6f5f2; --panel:#fffefc; --panel2:#efede8; --line:#e3dfd8; --line2:#d3cec5;
    --ink:#1b1a17; --ink2:#5d5850; --ink3:#8d877d;
    --accent:oklch(0.48 0.13 var(--hue)); --accentSoft:oklch(0.94 0.035 var(--hue)); --accentInk:#fff;
    --ok:oklch(0.50 0.12 155); --okSoft:oklch(0.94 0.05 155);
    --warn:oklch(0.55 0.13 70); --warnSoft:oklch(0.94 0.06 70);
    --bad:oklch(0.52 0.17 22); --badSoft:oklch(0.95 0.04 22);
    /* Donut segments. Six hues at one lightness and one chroma, so no slice
       shouts louder than another and the ring reads as one object. They are
       categorical - which persona - and never a scale. */
    --s1:oklch(0.52 0.13 155); --s2:oklch(0.55 0.14 258);
    --s3:oklch(0.62 0.13 70);  --s4:oklch(0.55 0.14 310);
    --s5:oklch(0.58 0.10 215); --s6:oklch(0.58 0.15 25);
    --pad:14px; --gap:12px; --r:10px;
    --sans:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;
    --mono:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;
    color-scheme: light;
  }
  :root[data-density="luftig"]{ --pad:20px; --gap:18px; }
  :root[data-density="tett"]{ --pad:14px; --gap:12px; }

  /* Dark by preference for anyone who has not chosen, ... */
  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]){
      --bg:#121214; --panel:#1a1a1d; --panel2:#232327; --line:#2d2d33; --line2:#3a3a41;
      --ink:#edeae5; --ink2:#a8a39b; --ink3:#7a756d;
      --accent:oklch(0.72 0.13 var(--hue)); --accentSoft:oklch(0.32 0.07 var(--hue)); --accentInk:#101014;
      --ok:oklch(0.75 0.14 155); --okSoft:oklch(0.30 0.06 155);
      --warn:oklch(0.80 0.13 78); --warnSoft:oklch(0.32 0.06 78);
      --bad:oklch(0.70 0.16 22); --badSoft:oklch(0.30 0.07 22);
      --s1:oklch(0.74 0.13 155); --s2:oklch(0.72 0.13 258);
      --s3:oklch(0.80 0.12 70);  --s4:oklch(0.74 0.13 310);
      --s5:oklch(0.76 0.10 215); --s6:oklch(0.72 0.14 25);
      color-scheme: dark;
    }
  }
  /* ... and by choice for anyone who has. */
  :root[data-theme="dark"]{
    --bg:#121214; --panel:#1a1a1d; --panel2:#232327; --line:#2d2d33; --line2:#3a3a41;
    --ink:#edeae5; --ink2:#a8a39b; --ink3:#7a756d;
    --accent:oklch(0.72 0.13 var(--hue)); --accentSoft:oklch(0.32 0.07 var(--hue)); --accentInk:#101014;
    --ok:oklch(0.75 0.14 155); --okSoft:oklch(0.30 0.06 155);
    --warn:oklch(0.80 0.13 78); --warnSoft:oklch(0.32 0.06 78);
    --bad:oklch(0.70 0.16 22); --badSoft:oklch(0.30 0.07 22);
    --s1:oklch(0.74 0.13 155); --s2:oklch(0.72 0.13 258);
    --s3:oklch(0.80 0.12 70);  --s4:oklch(0.74 0.13 310);
    --s5:oklch(0.76 0.10 215); --s6:oklch(0.72 0.14 25);
    color-scheme: dark;
  }

  *{ box-sizing:border-box; }
  html,body{ margin:0; padding:0; background:var(--bg); color:var(--ink);
             font-family:var(--sans); font-size:14px;
             font-variant-numeric:tabular-nums; -webkit-font-smoothing:antialiased; }
  a{ color:var(--accent); text-decoration:none; }
  a:hover{ color:var(--ink); text-decoration:underline; }
  button,select,input,textarea{ font-family:inherit; font-size:inherit; color:inherit; }
  :focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }
  table{ border-collapse:collapse; width:100%; }
  h1{ margin:0; font-size:20px; font-weight:700; letter-spacing:-0.01em; }
  h2{ margin:0; font-size:14px; font-weight:600; }
  [hidden]{ display:none !important; }

  /* ---------------------------------------------------------------- shell */
  .shell{ min-height:100vh; display:flex; background:var(--bg); }
  /* overflow-y: the nav grew a fifth group. On a short window the list has to
     be able to scroll inside its own column rather than push the logout button
     off the bottom of the screen. */
  .side{ width:216px; flex:0 0 216px; border-right:1px solid var(--line);
         background:var(--panel); display:flex; flex-direction:column; gap:2px;
         padding:14px 10px; position:sticky; top:0; height:100vh;
         overflow-y:auto; scrollbar-width:thin;
         scrollbar-color:var(--line2) transparent; }
  .brand{ display:flex; align-items:center; gap:8px; padding:4px 8px 14px;
          font-family:var(--mono); font-size:12.5px; letter-spacing:0.01em; }
  .dot{ width:9px; height:9px; border-radius:50%; background:var(--ok);
        box-shadow:0 0 0 4px var(--okSoft); flex:0 0 auto; }
  .dot.warn{ background:var(--warn); box-shadow:0 0 0 4px var(--warnSoft); }
  .dot.bad{ background:var(--bad); box-shadow:0 0 0 4px var(--badSoft); }
  /* A dot + label read as one status pill (Innstillinger: Tofaktor). */
  .statusline{ display:flex; align-items:center; gap:10px; }
  .statusline-text{ font-size:13px; font-weight:500; color:var(--ink); }
  .side-label{ font-size:10.5px; text-transform:uppercase; letter-spacing:0.05em;
               color:var(--ink3); padding:12px 8px 4px; }
  .side-label.first{ padding-top:6px; }
  .nav-item{ display:flex; align-items:center; gap:9px; padding:8px; border:0;
             border-radius:8px; background:transparent; color:var(--ink2);
             font-size:13.5px; text-align:left; cursor:pointer; width:100%; }
  .nav-item .pip{ width:6px; height:6px; border-radius:2px; background:currentColor;
                  opacity:0.7; flex:0 0 auto; }
  .nav-item:hover{ background:var(--panel2); color:var(--ink); text-decoration:none; }
  .nav-item[aria-current="page"]{ background:var(--accentSoft); color:var(--accent);
                                  font-weight:600; }
  .nav-badge{ margin-left:auto; font-family:var(--mono); font-size:11px;
              background:var(--warnSoft); color:var(--warn); border-radius:999px;
              padding:1px 7px; }
  .side-foot{ margin-top:auto; display:flex; flex-direction:column; gap:6px;
              padding-top:12px; border-top:1px solid var(--line); }
  .side-foot form{ margin:0; }
  .side-btn{ display:flex; align-items:center; justify-content:space-between;
             gap:8px; width:100%; padding:8px; border:1px solid var(--line);
             border-radius:8px; background:transparent; color:var(--ink2);
             font-size:12.5px; text-align:left; cursor:pointer; }
  .side-btn:hover{ background:var(--panel2); color:var(--ink); text-decoration:none; }
  .side-btn .val{ font-family:var(--mono); font-size:11.5px; color:var(--ink); }
  .main{ flex:1; min-width:0; display:flex; flex-direction:column; }
  .page{ padding:16px; display:flex; flex-direction:column; gap:var(--gap);
         max-width:1360px; width:100%; }
  .stack{ display:flex; flex-direction:column; gap:var(--gap); }

  /* --------------------------------------------------------------- stripe */
  .stripe{ position:sticky; top:0; z-index:5; display:flex; align-items:center;
           gap:14px; padding:9px 16px; background:var(--panel);
           border-bottom:1px solid var(--line); font-size:12.5px; }
  html[data-stripe="off"] .stripe{ display:none; }
  .stripe-item{ display:flex; align-items:center; gap:6px; }
  .stripe-item .lbl{ color:var(--ink2); }
  .stripe-item .val{ font-family:var(--mono); }
  .stripe-sep{ color:var(--line2); }
  .stripe-right{ margin-left:auto; display:flex; align-items:center; gap:10px; }
  .stripe .clock{ font-family:var(--mono); color:var(--ink3); }
  .stripe .pill{ padding:4px 10px; border:1px solid var(--line); border-radius:999px;
                 background:transparent; color:var(--ink2); font-size:11.5px;
                 cursor:pointer; }
  .stripe .pill:hover{ background:var(--panel2); color:var(--ink); text-decoration:none; }

  /* The theme control: one subtle icon at the top right, on every size. It
     shows the theme it switches TO - a sun while the page is dark, a moon
     while it is light - and which one that is, is decided by the same three
     states the token block uses, in CSS, so it is correct before the script
     runs and never flashes the wrong icon. */
  .iconbtn{ display:inline-flex; align-items:center; justify-content:center;
            width:28px; height:28px; padding:0; border:1px solid var(--line);
            border-radius:8px; background:transparent; color:var(--ink3);
            cursor:pointer; }
  .iconbtn:hover{ background:var(--panel2); color:var(--ink); }
  .iconbtn svg{ display:block; }
  /* The sun/moon swap is keyed on the toggle attribute, not on .iconbtn, so
     every theme control (the stripe button and the bottom-nav one) shows the
     right glyph from the same three states with no extra script. */
  [data-theme-toggle] .icon-sun{ display:none; }
  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]) [data-theme-toggle] .icon-sun{ display:block; }
    :root:not([data-theme="light"]) [data-theme-toggle] .icon-moon{ display:none; }
  }
  :root[data-theme="dark"] [data-theme-toggle] .icon-sun{ display:block; }
  :root[data-theme="dark"] [data-theme-toggle] .icon-moon{ display:none; }

  /* ------------------------------------------------------------ page head */
  .page-head{ display:flex; align-items:flex-end; gap:12px; flex-wrap:wrap; }
  .page-head .sub{ font-size:12.5px; color:var(--ink2); margin-top:3px; max-width:70ch; }
  .page-head .aside{ margin-left:auto; display:flex; gap:8px; align-items:center;
                     flex-wrap:wrap; }
  .lede{ font-size:12.5px; color:var(--ink3); }

  /* ----------------------------------------------------------------- tabs */
  .tabs{ display:flex; gap:6px; overflow-x:auto; padding-bottom:2px; }
  .tab{ white-space:nowrap; padding:7px 13px; border:1px solid var(--line);
        border-radius:999px; background:var(--panel); color:var(--ink2);
        font-size:13px; cursor:pointer; }
  .tab:hover{ border-color:var(--line2); color:var(--ink); text-decoration:none; }
  .tab[aria-selected="true"]{ background:var(--accent); color:var(--accentInk);
                              border-color:var(--accent); }

  /* ---------------------------------------------------------------- cards */
  .card{ background:var(--panel); border:1px solid var(--line);
         border-radius:var(--r); padding:var(--pad); }
  .card.flush{ padding:0; overflow:hidden; }
  .card.col{ display:flex; flex-direction:column; gap:10px; }
  .card-head{ display:flex; align-items:baseline; gap:8px; padding:var(--pad);
              border-bottom:1px solid var(--line); flex-wrap:wrap; }
  .card-head .count{ font-family:var(--mono); font-size:11.5px; color:var(--ink3); }
  .card-head .note{ font-size:11.5px; color:var(--ink3); }
  .card-head .aside{ margin-left:auto; display:flex; gap:8px; align-items:center; }
  /* A raw-data card whose head sits flush with the block below it (CSP forbids
     inline style attributes, so the variant lives here). */
  .card-head.flat{ padding:0 0 6px; border-bottom:0; }
  .card-head.flat h2{ margin:0; }
  .card-body{ padding:var(--pad); display:flex; flex-direction:column; gap:10px; }
  .hint{ font-size:11.5px; color:var(--ink3); line-height:1.45; }
  .muted{ color:var(--ink2); font-size:12.5px; }
  .empty{ padding:var(--pad); color:var(--ink3); font-size:13px; }

  .grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
         gap:var(--gap); }
  .grid.tight{ grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); }
  .grid.wide{ grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); }
  .split{ display:grid; grid-template-columns:minmax(0,340px) minmax(0,1fr);
          gap:var(--gap); align-items:start; }
  .split.narrow{ grid-template-columns:minmax(0,300px) minmax(0,1fr); }
  .split.flip{ grid-template-columns:minmax(0,1fr) minmax(0,260px); }

  /* --------------------------------------------------------------- source */
  .source .top{ display:flex; align-items:center; gap:7px; }
  .source .name{ font-size:13.5px; font-weight:600; }
  .source .big{ font-family:var(--mono); font-size:22px; letter-spacing:-0.01em; }
  .source .big .unit{ font-size:12px; color:var(--ink3); }
  .source .line{ font-size:12px; color:var(--ink2); }
  .source .src{ font-size:11.5px; color:var(--ink3); font-family:var(--mono); }
  .stat .k{ font-size:10.5px; text-transform:uppercase; letter-spacing:0.07em;
            color:var(--ink3); }
  .stat .v{ font-family:var(--mono); font-size:18px; margin-top:4px; }
  .stat .s{ font-size:11.5px; color:var(--ink3); }

  /* ---------------------------------------------------------------- chips */
  .chip{ display:inline-block; font-size:11.5px; color:var(--ink2);
         background:var(--panel2); border-radius:999px; padding:2px 8px;
         white-space:nowrap; }
  .chip.ok{ color:var(--ok); background:var(--okSoft); }
  .chip.warn{ color:var(--warn); background:var(--warnSoft); }
  .chip.bad{ color:var(--bad); background:var(--badSoft); }
  .chip.accent{ color:var(--accent); background:var(--accentSoft); }
  .chip.plain{ background:transparent; border:1px solid var(--line);
               color:var(--ink3); font-family:var(--mono); }
  .chip.mono{ font-family:var(--mono); }
  .lvl{ display:inline-block; font-size:11.5px; border-radius:6px; padding:2px 8px;
        color:var(--ink3); }
  .lvl.full,.lvl.read{ color:var(--ok); background:var(--okSoft); }
  .lvl.own{ color:var(--accent); background:var(--accentSoft); }
  .lvl.shared,.lvl.limited{ color:var(--warn); background:var(--warnSoft); }
  .lvl.decide{ color:var(--bad); background:var(--badSoft); }
  .chips{ display:flex; gap:6px; flex-wrap:wrap; align-items:center; }
  .mono{ font-family:var(--mono); }
  code{ font-family:var(--mono); background:var(--panel2); border-radius:5px;
        padding:1px 5px; font-size:0.95em; }
  .hint p{ margin:0; }
  .tag{ font-family:var(--mono); font-size:12px; background:var(--panel2);
        border-radius:6px; padding:2px 7px; }

  /* --------------------------------------------------------------- tables */
  /* The two places something may scroll sideways: a wide table and the tab
     row. Thin, tinted bars so they read as an affordance rather than as a
     page that broke; overscroll-behavior keeps the gesture off the history. */
  .scroll{ overflow-x:auto; }
  .scroll,.tabs{ scrollbar-width:thin; scrollbar-color:var(--line2) transparent;
                 overscroll-behavior-x:contain; }
  .scroll::-webkit-scrollbar,.tabs::-webkit-scrollbar{ height:6px; }
  .scroll::-webkit-scrollbar-track,.tabs::-webkit-scrollbar-track{
        background:transparent; }
  .scroll::-webkit-scrollbar-thumb,.tabs::-webkit-scrollbar-thumb{
        background:var(--line2); border-radius:3px; }
  .tbl{ font-size:13px; }
  .tbl th{ text-align:left; padding:8px 10px; font-size:10.5px; font-weight:500;
           text-transform:uppercase; letter-spacing:0.07em; color:var(--ink3);
           border-bottom:1px solid var(--line); white-space:nowrap; }
  .tbl td{ padding:10px; vertical-align:top; }
  .tbl tbody tr{ border-bottom:1px solid var(--line); }
  .tbl tbody tr:last-child{ border-bottom:0; }
  .tbl tbody tr:hover{ background:var(--panel2); }
  .tbl th:first-child,.tbl td:first-child{ padding-left:var(--pad); }
  .tbl th:last-child,.tbl td:last-child{ padding-right:var(--pad); }
  .tbl .r{ text-align:right; }
  .tbl td form{ display:inline-block; margin:0 0 0 8px; }
  .tbl .nw{ white-space:nowrap; }
  .tbl .t{ font-family:var(--mono); font-size:12px; color:var(--ink2);
           white-space:nowrap; }
  .tbl .t .rel{ color:var(--ink3); font-size:11px; }
  .tbl.log{ font-size:12.5px; }
  .tbl.log td{ padding:7px 10px; }
  .w820{ min-width:820px; } .w720{ min-width:720px; } .w660{ min-width:660px; }
  .w640{ min-width:640px; }

  /* ---------------------------------------------------------------- forms */
  .field{ display:flex; flex-direction:column; gap:4px; font-size:11px;
          text-transform:uppercase; letter-spacing:0.07em; color:var(--ink3); }
  .field > input,.field > select,.field > textarea{
        padding:8px 9px; border:1px solid var(--line2); border-radius:8px;
        background:var(--bg); font-size:13.5px; letter-spacing:0;
        text-transform:none; color:var(--ink); width:100%; }
  .field > textarea{ resize:vertical; padding:9px; }
  .field.num > input{ font-family:var(--mono); }
  .field.w96{ width:96px; } .field.w84{ width:84px; }
  .formrow{ display:flex; gap:10px; flex-wrap:wrap; align-items:flex-end; }
  .btn{ padding:9px 16px; border:1px solid transparent; border-radius:8px;
        background:var(--accent); color:var(--accentInk); font-size:13.5px;
        font-weight:600; cursor:pointer; white-space:nowrap; }
  .btn:hover{ text-decoration:none; filter:brightness(1.06); }
  .btn.block{ display:block; width:100%; padding:10px; }
  .btn.ghost{ background:transparent; border-color:var(--line2); color:var(--ink2);
              font-weight:400; }
  .btn.ghost:hover{ background:var(--panel2); color:var(--ink); }
  .btn.ok{ background:var(--ok); color:#fff; border-color:var(--ok); }
  .btn.deny{ background:transparent; border-color:var(--line2); color:var(--bad);
             font-weight:600; }
  .btn.small{ padding:4px 9px; border:1px solid var(--line); border-radius:6px;
              background:transparent; color:var(--bad); font-size:11.5px;
              font-weight:400; }
  .btn.pill{ padding:5px 11px; border:1px solid var(--line); border-radius:999px;
             background:transparent; color:var(--ink2); font-size:12px;
             font-weight:400; }
  .btn.pill:hover{ background:var(--panel2); color:var(--ink); }
  .btn.tool{ padding:7px 12px; border:1px solid var(--line); border-radius:8px;
             background:var(--panel); color:var(--ink2); font-family:var(--mono);
             font-size:12px; font-weight:400; }
  .btn.tool[aria-pressed="true"]{ background:var(--accent); color:var(--accentInk);
                                  border-color:var(--accent); }
  .btn:disabled{ opacity:0.45; cursor:not-allowed; filter:none; }
  .row2{ display:flex; gap:8px; }
  .row2 > *{ flex:1; }
  .seg{ display:flex; gap:6px; }
  .seg input{ position:absolute; opacity:0; width:0; height:0; }
  .seg label{ padding:8px 11px; border:1px solid var(--line); border-radius:8px;
              background:var(--panel); color:var(--ink2); font-size:12.5px;
              cursor:pointer; }
  .seg input:checked + label{ background:var(--accent); color:var(--accentInk);
                              border-color:var(--accent); }
  .seg input:focus-visible + label{ outline:2px solid var(--accent);
                                    outline-offset:2px; }
  .caps{ font-size:11px; text-transform:uppercase; letter-spacing:0.07em;
         color:var(--ink3); }

  /* -------------------------------------------------------------- preview */
  .panel{ border:1px solid var(--line); border-radius:var(--r); overflow:hidden; }
  .panel-head{ display:flex; align-items:center; gap:8px; flex-wrap:wrap;
               padding:10px var(--pad); background:var(--panel2);
               border-bottom:1px solid var(--line); }
  .panel-head .name{ font-family:var(--mono); font-size:12.5px; font-weight:500; }
  .panel-head .aside{ margin-left:auto; }
  pre{ margin:0; background:var(--panel2); border:1px solid var(--line);
       border-radius:8px; padding:12px; overflow-x:auto; font-family:var(--mono);
       font-size:12px; line-height:1.5; color:var(--ink2); white-space:pre-wrap;
       overflow-wrap:anywhere; }
  ul.readable{ margin:0; padding-left:18px; display:flex; flex-direction:column;
               gap:4px; font-size:13px; color:var(--ink2); }
  .quote{ border-left:2px solid var(--accent); padding:2px 0 2px 12px; }
  .quote .txt{ font-size:15px; margin-top:3px; }
  .soft{ background:var(--panel2); border-radius:8px; padding:12px; font-size:13px;
         line-height:1.55; color:var(--ink2); }
  .kv{ display:grid; grid-template-columns:auto 1fr; gap:4px 12px; font-size:13px; }
  .kv .k{ color:var(--ink3); }

  /* --------------------------------------------------------------- toast
     A transient receipt, bottom-right, the way Brain's sonner reads. The
     server hands the shell one line (flash) and a severity (flash_kind); the
     shell's script also raises one on the fly for the copy buttons. Fades in,
     leaves on its own after a few seconds, or on a click. */
  .toast-region{ position:fixed; right:16px; bottom:16px; z-index:60;
                 display:flex; flex-direction:column; gap:8px; align-items:flex-end;
                 pointer-events:none; max-width:min(360px, calc(100vw - 32px)); }
  .toast{ pointer-events:auto; display:flex; align-items:center; gap:8px;
          padding:10px 12px; border-radius:10px; border:1px solid var(--line);
          background:var(--panel); color:var(--ink); font-size:12.5px;
          line-height:1.4; box-shadow:0 6px 20px rgba(0,0,0,0.14);
          cursor:pointer; opacity:0; transform:translateY(6px);
          transition:opacity .18s ease, transform .18s ease; max-width:100%; }
  .toast.show{ opacity:1; transform:translateY(0); }
  .toast::before{ content:""; width:8px; height:8px; border-radius:50%;
                  flex:0 0 auto; background:var(--ok);
                  box-shadow:0 0 0 4px var(--okSoft); }
  .toast.ok{ border-color:var(--ok); }
  .toast.ok::before{ background:var(--ok); box-shadow:0 0 0 4px var(--okSoft); }
  .toast.warn{ border-color:var(--warn); }
  .toast.warn::before{ background:var(--warn); box-shadow:0 0 0 4px var(--warnSoft); }
  .toast .msg{ flex:1 1 auto; overflow-wrap:anywhere; }
  @media (max-width:880px){
    .toast-region{ right:12px; left:12px; bottom:90px; max-width:none;
                   align-items:stretch; }
  }
  @media (prefers-reduced-motion: reduce){
    .toast{ transition:opacity .18s ease; transform:none; }
    .toast.show{ transform:none; }
  }

  /* ------------------------------------------------------------- copy btn
     A small reusable action next to something worth copying. Any [data-copy]
     button is wired by the shell script; the target text is the element named
     by data-copy (an id) or the button's own previous sibling. */
  .copybtn{ display:inline-flex; align-items:center; gap:5px; padding:4px 10px;
            border:1px solid var(--line); border-radius:999px; background:transparent;
            color:var(--ink2); font:inherit; font-size:11.5px; cursor:pointer; }
  .copybtn:hover{ background:var(--panel2); color:var(--ink); border-color:var(--line2); }

  /* --------------------------------------------------------------- modal
     Native <dialog>, opened by [data-dialog-open] and by the confirm helper.
     Brain reaches for a Radix dialog here; a native <dialog> gives the same
     focus-trap, Esc-to-close and inert background for free, and takes voice's
     own tokens and radius so the sheet reads as one panel with the rest. The
     <dialog> itself is only the centring frame - transparent, no chrome; the
     visual panel is the .card inside it, which already carries panel/border/
     radius, so a form that was a .card on the page needs no reshaping to sit
     in a modal. On a phone it fills the width rather than floating narrow. */
  dialog.modal{ padding:0; border:0; background:transparent; color:var(--ink);
                max-width:min(560px, calc(100vw - 24px)); width:100%; }
  dialog.modal.wide{ max-width:min(720px, calc(100vw - 24px)); }
  dialog.modal::backdrop{ background:rgba(0,0,0,0.5); backdrop-filter:blur(1px); }
  dialog.modal > .card{ max-height:calc(100vh - 48px); overflow-y:auto;
                        box-shadow:0 14px 44px rgba(0,0,0,0.24);
                        scrollbar-width:thin;
                        scrollbar-color:var(--line2) transparent; }
  dialog.modal[open]{ animation:modal-in .18s ease; }
  @keyframes modal-in{ from{ opacity:0; transform:translateY(6px) scale(0.98); }
                       to{ opacity:1; transform:none; } }
  @media (prefers-reduced-motion: reduce){
    dialog.modal[open]{ animation:none; }
  }
  /* A small square close affordance in a modal header, matching the stripe's
     icon button so every corner-x on the panel reads the same. */
  .iconx{ display:inline-flex; align-items:center; justify-content:center;
          width:28px; height:28px; padding:0; border:1px solid var(--line);
          border-radius:8px; background:transparent; color:var(--ink3);
          cursor:pointer; flex:0 0 auto; }
  .iconx:hover{ background:var(--panel2); color:var(--ink); }
  .iconx svg{ display:block; }
  .modal-text{ font-size:13.5px; color:var(--ink2); line-height:1.5; margin:0; }
  .modal-head{ display:flex; align-items:center; gap:8px; }
  .modal-head .name-lg{ flex:1; min-width:0; }
  @media (max-width:880px){
    dialog.modal, dialog.modal.wide{ max-width:none; width:calc(100vw - 20px); }
  }

  /* ------------------------------------------------------------- approval */
  .approval{ border-left:3px solid var(--warn); }
  .approval details > summary{ cursor:pointer; }
  .approval details[open] > summary{ margin-bottom:8px; }
  .approval .code{ font-family:var(--mono); font-size:22px; letter-spacing:0.06em; }

  /* ---------------------------------------------------------------- calls */
  .listrow{ display:flex; align-items:center; gap:10px; flex-wrap:wrap;
            padding:9px 10px; border:1px solid var(--line); border-radius:8px;
            font-size:13px; }
  .listrow:hover{ background:var(--panel2); }
  .listrow .aside{ margin-left:auto; font-size:12px; color:var(--ink2);
                   font-family:var(--mono); }
  .grouplist{ display:flex; flex-direction:column; gap:6px; margin-top:10px; }
  details.group > summary{ list-style:none; cursor:pointer; }
  details.group > summary::-webkit-details-marker{ display:none; }
  details.group{ margin-bottom:6px; }
  details.group[open] > summary .listrow{ border-color:var(--line2); }
  .mt-title{ margin-top:10px; }
  .stat .v.id{ font-size:12px; color:var(--ink2); word-break:break-all; }
  .transcript{ max-width:820px; gap:12px; }
  .turn{ display:flex; gap:10px; }
  .turn .when{ flex:0 0 62px; font-family:var(--mono); font-size:11px;
               color:var(--ink3); padding-top:3px; }
  .turn .who{ font-size:10.5px; letter-spacing:0.06em; text-transform:uppercase; }
  .turn.agent .who{ color:var(--accent); }
  .turn .bubble{ flex:1; min-width:0; background:var(--panel2); border-radius:10px;
                 padding:10px 12px; font-size:13.5px; line-height:1.5;
                 white-space:pre-wrap; overflow-wrap:anywhere; }
  .turn.agent .bubble{ background:var(--accentSoft); }
  .turn.event{ align-items:center; }
  .turn.event .when{ padding-top:0; }

  /* -------------------------------------------------------------- persona */
  .name-lg{ font-size:15px; font-weight:600; }
  .stack-tight{ display:flex; flex-direction:column; gap:6px; margin-top:6px; }
  .stat .v.txt{ font-family:var(--sans); font-size:14px; }
  .plist{ display:flex; flex-direction:column; }
  .plist a{ display:flex; align-items:center; gap:8px; padding:10px var(--pad);
            border-bottom:1px solid var(--line); color:var(--ink);
            font-size:13.5px; }
  .plist a:last-child{ border-bottom:0; }
  .plist a:hover{ background:var(--panel2); text-decoration:none; }
  .plist a[aria-current="true"]{ background:var(--accentSoft); font-weight:600; }
  .plist .id{ font-family:var(--mono); font-size:11.5px; color:var(--ink3);
              font-weight:400; }
  .plist .num{ margin-left:auto; font-family:var(--mono); font-size:11.5px;
               color:var(--ink2); font-weight:400; }
  .access{ display:flex; align-items:center; gap:10px; padding:8px 10px;
           background:var(--panel2); border-radius:8px; }
  .access .name{ font-family:var(--mono); font-size:12.5px; flex:1; min-width:0; }
  .access .opts{ display:flex; gap:4px; flex-wrap:wrap; }
  .access input{ position:absolute; opacity:0; width:0; height:0; }
  .access .opt{ font-size:11.5px; color:var(--ink3); border:1px solid var(--line2);
                border-radius:6px; padding:2px 8px; cursor:pointer; }
  .access .opt:hover{ border-color:var(--ink3); }
  /* The granted level is coloured by what it means, exactly as the policy
     matrix colours it: denied is red, a narrowed view amber, a full one green. */
  .access input:checked + .opt{ border-color:currentColor; }
  .access input:checked + .opt.none{ color:var(--bad); background:var(--badSoft); }
  .access input:checked + .opt.shared,
  .access input:checked + .opt.limited{ color:var(--warn);
                                        background:var(--warnSoft); }
  .access input:checked + .opt.full,
  .access input:checked + .opt.read{ color:var(--ok); background:var(--okSoft); }
  .access input:checked + .opt.own{ color:var(--accent);
                                    background:var(--accentSoft); }
  .access input:checked + .opt.decide{ color:var(--bad); background:var(--badSoft); }
  .access input:focus-visible + .opt{ outline:2px solid var(--accent);
                                      outline-offset:2px; }
  .access input:disabled + .opt{ cursor:not-allowed; }
  /* A field the service holds fixed. The lock that counts is on the write
     path; this only says so before the form is posted. */
  .access.locked{ opacity:0.6; }
  .check{ display:flex; align-items:center; gap:7px; font-size:12.5px;
          color:var(--ink2); cursor:pointer; }
  .check input{ width:15px; height:15px; accent-color:var(--accent);
                cursor:pointer; }
  .check input:disabled,.check input:disabled + span{ cursor:not-allowed;
                                                      opacity:0.6; }
  .field > input:disabled,.field > select:disabled,.field > textarea:disabled{
        opacity:0.6; cursor:not-allowed; }

  /* ------------------------------------------------------------ openings */
  /* One row per scripted opening. The sentence IS the control, so the text
     field runs the width of the row with the two buttons beside it, and the
     line as it will actually be spoken sits underneath - that second line is
     the one that matters, because <navn> tells you nothing until it has a
     name in it. */
  .openrow{ display:flex; flex-direction:column; gap:6px; padding:9px 10px;
            border:1px solid var(--line); border-radius:8px; }
  .openrow:hover{ background:var(--panel2); }
  .openrow > .edit{ display:flex; gap:8px; align-items:flex-end; }
  .openrow .line{ flex:1; min-width:0; }
  .openrow .spoken{ font-size:12.5px; color:var(--ink2); }
  .openacc{ border-bottom:1px solid var(--line); }
  .openacc summary{ cursor:pointer; padding:10px 14px; font-weight:600;
    font-size:13px; user-select:none; }
  .openacc summary .count{ margin-left:6px; }
  .openacc[open] summary{ border-bottom:1px solid var(--line); }
  .grpchecks{ display:inline-flex; flex-wrap:wrap; gap:4px; }
  .pillcheck{ font-size:11px; border:1px solid var(--line); border-radius:999px;
    padding:2px 8px; cursor:pointer; user-select:none; white-space:nowrap; }
  .pillcheck input{ margin:0 4px 0 0; vertical-align:middle; }
  .openrow .who{ font-family:var(--mono); font-size:11px;
                         color:var(--ink3); }

  /* --------------------------------------------------------------- voices */
  /* The play button is the point of this page: a voice's name says nothing,
     and the description is optional. So the browser's own player leads each
     row, at a size that reads as the primary control rather than as a
     footnote, and the text sits beside it. */
  .voicecard{ display:flex; flex-direction:column; gap:10px; }
  .voicecard.is-default{ border-color:var(--accent); }
  .voicetop{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
  .audiobox{ flex:0 0 auto; display:flex; align-items:center; min-height:40px; }
  .voicemeta{ flex:1; min-width:180px; display:flex; flex-direction:column;
              gap:3px; }
  audio.preview{ width:280px; max-width:100%; height:40px; }
  .field.grow{ flex:1; min-width:180px; }
  .formrow > .btn{ align-self:flex-end; }
  /* Tempo: the number is the field, the slider is the grip. They sit on one
     line so the pair reads as a single control rather than two settings. */
  .speedbox{ flex:0 0 auto; }
  .speedrow{ display:flex; align-items:center; gap:8px; }
  .speedrow > .speednum{ width:76px; flex:0 0 auto; font-family:var(--mono);
        padding:8px 9px; border:1px solid var(--line2); border-radius:8px;
        background:var(--bg); font-size:13.5px; color:var(--ink); }
  .speedrow > .speedrange{ width:118px; flex:0 0 auto; accent-color:var(--accent);
        margin:0; cursor:pointer; }
  @media (max-width:880px){
    audio.preview{ width:100%; }
    .audiobox{ width:100%; }
    .speedbox{ width:100%; }
    .speedrow > .speedrange{ flex:1; width:auto; }
  }

  /* ------------------------------------------------------------ dashboard */
  /* Two gauges side by side, one column on a phone. A third gauge is a third
     card in this grid: it wraps onto the next row rather than sitting in an
     empty third column, so there is room for one without a hole while there
     is not. */
  .gauges{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
           gap:var(--gap); align-items:stretch; }
  .card.col > .card-head.flush-head{ padding:0; border-bottom:0; }
  .ring-wrap{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
  .ring{ flex:0 0 auto; }
  /* The ring starts at twelve o'clock. Rotating the group rather than each
     circle keeps every dash offset measured from the same place. */
  .donut{ transform:rotate(-90deg); transform-origin:50% 50%; }
  .ring circle{ fill:none; stroke-width:14; }
  .ring .track{ stroke:var(--panel2); }
  .ring .arc{ stroke:var(--accent); }
  .ring .arc.ok{ stroke:var(--ok); }
  .ring .arc.warn{ stroke:var(--warn); }
  .ring .arc.bad{ stroke:var(--bad); }
  .ring .arc.s1{ stroke:var(--s1); } .ring .arc.s2{ stroke:var(--s2); }
  .ring .arc.s3{ stroke:var(--s3); } .ring .arc.s4{ stroke:var(--s4); }
  .ring .arc.s5{ stroke:var(--s5); } .ring .arc.s6{ stroke:var(--s6); }
  .ring-value{ fill:var(--ink); font-family:var(--mono); font-size:24px;
               font-weight:600; text-anchor:middle; dominant-baseline:middle; }
  .ring-value.dim{ fill:var(--ink3); }
  .ring-unit{ fill:var(--ink3); font-family:var(--mono); font-size:11px;
              text-anchor:middle; dominant-baseline:middle; }
  .ring-side{ flex:1; min-width:150px; display:flex; flex-direction:column;
              gap:3px; }
  .ring-side .big{ font-family:var(--mono); font-size:22px;
                   letter-spacing:-0.01em; }
  .ring-side .big.dim{ font-size:15px; color:var(--ink3); }
  .ring-side .line{ font-size:12.5px; color:var(--ink2); }
  .ring-side .line.dim{ color:var(--ink3); }
  .ring-side .src{ font-size:11.5px; color:var(--ink3); font-family:var(--mono); }
  .legend{ list-style:none; margin:0; padding:0; display:flex;
           flex-direction:column; gap:5px; font-size:12.5px; }
  .legend li{ display:flex; align-items:center; gap:8px; }
  .legend .who{ color:var(--ink2); min-width:0; overflow:hidden;
                text-overflow:ellipsis; white-space:nowrap; }
  .legend .num{ margin-left:auto; font-family:var(--mono); font-size:12px;
                color:var(--ink); white-space:nowrap; }
  .swatch{ width:10px; height:10px; border-radius:3px; flex:0 0 auto; }
  .swatch.s1{ background:var(--s1); } .swatch.s2{ background:var(--s2); }
  .swatch.s3{ background:var(--s3); } .swatch.s4{ background:var(--s4); }
  .swatch.s5{ background:var(--s5); } .swatch.s6{ background:var(--s6); }
  .today{ margin:0; font-family:var(--mono); font-size:12.5px;
          color:var(--ink2); }

  /* The two one-line lists. Deliberately not tables: one row is one fact, and
     a table's header row would be three quarters of the ink. */
  .calllist,.notelist{ list-style:none; margin:0; padding:0; display:flex;
                       flex-direction:column; }
  .calllist li,.notelist li{ border-bottom:1px solid var(--line); }
  .calllist li:last-child,.notelist li:last-child{ border-bottom:0; }
  .calllist a{ display:flex; align-items:center; gap:12px;
               padding:10px var(--pad); color:var(--ink); font-size:13.5px; }
  .calllist a:hover{ background:var(--panel2); text-decoration:none; }
  .calllist .num{ margin-left:auto; font-family:var(--mono); font-size:12.5px;
                  color:var(--ink2); white-space:nowrap; }
  .notelist li{ display:flex; align-items:center; gap:10px;
                padding:8px var(--pad); font-size:13.5px; }
  .notelist .who{ font-family:var(--mono); font-size:12px;
                  background:var(--panel2); border-radius:6px; padding:2px 7px;
                  flex:0 0 auto; }
  .notelist .msg{ flex:1; min-width:0; overflow:hidden;
                  text-overflow:ellipsis; white-space:nowrap;
                  color:var(--ink2); }
  .notelist form{ margin:0; flex:0 0 auto; }
  /* Shown only where the sidebar is not. The .card.col half is not
     redundant: that selector is two classes and would otherwise win. */
  .only-sm,.card.col.only-sm{ display:none; }

  /* ---------------------------------------------------------------- login */
  .login-wrap{ min-height:100vh; display:grid; place-items:center; padding:24px; }
  .login{ width:100%; max-width:360px; }
  .login form{ background:var(--panel); border:1px solid var(--line);
               border-radius:var(--r); padding:20px; display:flex;
               flex-direction:column; gap:12px; }
  .login .title{ font-size:17px; font-weight:600; }
  .login .totp{ font-family:var(--mono); font-size:16px; letter-spacing:0.3em; }
  .login .remember{ display:flex; align-items:center; gap:8px; font-size:12.5px;
                    color:var(--ink2); cursor:pointer; user-select:none; }
  .login .remember input{ width:16px; height:16px; margin:0; cursor:pointer;
                          accent-color:var(--accent); }
  .login .remember-note{ display:flex; align-items:center; gap:8px;
                         font-size:12.5px; color:var(--ink2); }
  .login .foot{ margin-top:12px; font-size:11.5px; color:var(--ink3);
                text-align:center; }
  .alert{ display:flex; align-items:center; gap:8px; background:var(--badSoft);
          color:var(--bad); border-radius:8px; padding:8px 10px; font-size:12.5px; }

  /* ----------------------------------------------------------- bottom nav */
  .bottomnav{ display:none; position:fixed; bottom:0; left:0; right:0; z-index:10;
              background:var(--panel); border-top:1px solid var(--line);
              padding:6px 4px 8px; }
  .bottomnav .nav-item{ flex:1; flex-direction:column; align-items:center; gap:3px;
                        padding:6px 2px; font-size:11px; text-align:center; }
  .bottomnav .nav-item .pip{ width:16px; height:3px; border-radius:2px; }
  .bottomnav form{ flex:1; margin:0; display:flex; }
  /* One theme control only, in the status stripe (Lasse 03.09.2026): the
     bottom nav had its own and it was one tap too many. The stripe can be
     hidden per browser; then the theme is set once and the stripe shown
     again when it needs changing. */

  @media (max-width:880px){
    .side{ display:none; }
    .bottomnav{ display:flex; }
    .shell{ padding-bottom:78px; }
    /* minmax(0,1fr), not 1fr: a bare 1fr track is min-width:auto, so a
       wide table inside it widens the column and the whole page scrolls
       sideways on a phone. */
    .split,.split.narrow,.split.flip{ grid-template-columns:minmax(0,1fr); }
    .gauges{ grid-template-columns:minmax(0,1fr); }
    .hide-sm{ display:none; }
    .only-sm,.card.col.only-sm{ display:flex; }
    /* The ring keeps its size; the numbers beside it go under it. */
    .ring-side{ flex:1 1 100%; }
    .stripe{ flex-wrap:wrap; gap:8px 12px; }
    .page{ padding:12px; }
  }
